tail calls
の機能で遊んでいますがBPF
、単純なコードが読み込まれていないようです:
struct bpf_map_def SEC("maps") jmp_table = {
.type = BPF_MAP_TYPE_PROG_ARRAY,
.key_size = sizeof(u32),
.value_size = sizeof(u32),
.max_entries = 8,
};
SEC("sockops")
int bpf1(struct bpf_sock_ops *sk_ops)
{
return 1;
}
SEC("sockops")
int bpf2(struct bpf_sock_ops *sk_ops)
{
return 1;
}
SEC("sockops")
int bpf3(struct bpf_sock_ops *sk_ops)
{
return 1;
}
SEC("sockops")
int bpf_main(struct bpf_sock_ops *sk_ops)
{
__u32 port = bpf_ntohl(sk_ops->remote_port);
switch (port) {
case 5000:
bpf_tail_call(sk_ops, &jmp_table, 1);
break;
case 6000:
bpf_tail_call(sk_ops, &jmp_table, 2);
break;
case 7000:
bpf_tail_call(sk_ops, &jmp_table, 3);
break;
}
sk_ops->reply = 0;
return 1;
}
char _license[] SEC("license") = "GPL";
u32 _version SEC("version") = LINUX_VERSION_CODE;
だから私はそれをコンパイルしてllv-3.8
ロードしましたbpftool
:
$ sudo ./bpftool prog load bpf_main.o /sys/fs/bpf/p1
libbpf: load bpf program failed: Invalid argument
libbpf: -- BEGIN DUMP LOG ---
libbpf:
unreachable insn 2
libbpf: -- END LOG --
libbpf: failed to load program 'sockops'
libbpf: failed to load object 'bpf_main.o'
Error: failed to load program
したがって、次のようman 2 bpf
に述べています。
EINVAL For BPF_PROG_LOAD, indicates an attempt to load an invalid program. eBPF programs can be deemed invalid due to unrecognized instructions, the use of reserved fields, jumps out of range, infinite loops or calls of unknown functions.
この小さな単純なプログラムの何が問題なのかわかりません。また、llvm-objdump
失敗します:
$ llvm-objdump-3.8 -arch-name=bpf -disassemble ./tcp_metrics_kern.o
./tcp_metrics_kern.o: file format ELF64-unknown
LLVM ERROR: error: no disassembler for target bpfel-unknown-unknown
更新 1
Qeole のアドバイスに従って にアップグレードしclang-5.0
、プログラムを再構築しましたが、今では別の方法で文句を言います:
$ sudo ./bpftool prog load bpf_main.o /sys/fs/bpf/p1
libbpf: relocation failed: no 10 section
Error: failed to load program
これで、ELF セクションを調査できます。
$ llvm-objdump-5.0 -disassemble -source ./bpf_main.o
./bpf_main.o: file format ELF64-BPF
Disassembly of section sockops:
bpf1:
0: b7 00 00 00 01 00 00 00 r0 = 1
1: 95 00 00 00 00 00 00 00 exit
bpf2:
2: b7 00 00 00 01 00 00 00 r0 = 1
3: 95 00 00 00 00 00 00 00 exit
bpf3:
4: b7 00 00 00 01 00 00 00 r0 = 1
5: 95 00 00 00 00 00 00 00 exit
bpf_main:
...
使用可能なセクションは次のとおりです。
$ llvm-objdump-5.0 -section-headers ./bpf_main.o
./bpf_main.o: file format ELF64-BPF
Sections:
Idx Name Size Address Type
0 00000000 0000000000000000
1 .strtab 000000a5 0000000000000000
2 .text 00000000 0000000000000000 TEXT DATA
3 sockops 000001f8 0000000000000000 TEXT DATA
4 .relsockops 00000030 0000000000000000
5 maps 0000001c 0000000000000000 DATA
6 .rodata.str1.16 00000021 0000000000000000 DATA
7 .rodata.str1.1 0000000e 0000000000000000 DATA
8 license 00000004 0000000000000000 DATA
9 version 00000004 0000000000000000 DATA
10 .eh_frame 00000090 0000000000000000 DATA
11 .rel.eh_frame 00000040 0000000000000000
12 .symtab 00000138 0000000000000000
bpftool
セクションが見つからないように見えます.eh_frame
か?
更新 2
私は実験を続けます:-) まず、libbpf
最新のコミットd77be68955475fc2321e73fe006240248f2f8fef
修正文字列比較で更新し、次にプログラムを再構築します-fno-asynchronous-unwind-tables
。これにはセクションは含まれません.eh_frame
。また、sockops0、sockops1 などの一意のセクション名を付けました。今はbpftool prog load ..
成功しますが、bpftool prog show
ダンプのみです。単一のプログラムで、最初に実行されるプログラムです。私の場合は bpf1() です。
現時点では、bpf_object__load_progs() が obj->nr_programs を 4 と報告していると言えますが、これは私の例では理にかなっています。