ebpf - 部分名称
ebpf - sections names
bpf
程序中的每个程序部分是否必须具有唯一的名称?例如,这个程序可以很好地编译 llvm-5.0
:
...
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;
但是,llvm-objdump
只报告了一个节目部分:
$ 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
是否有至少给出警告的编译器选项?
UPDATE - 所以我知道同一个 bpf 文件中提供的部分必须具有唯一的名称。在 bpf 程序驻留在不同的文件中并独立编译的情况下是否如此,以便它们可以加载并相互调用,例如tail calls
?
显然,编译器将同一部分中的所有内容串联起来(我简化了 bpf_main
以使其编译和测试)。
$ readelf -x sockops bpf_prog.o
Hex dump of section 'sockops':
0x00000000 b7000000 01000000 95000000 00000000 ................
0x00000010 b7000000 01000000 95000000 00000000 ................
0x00000020 b7000000 01000000 95000000 00000000 ................
0x00000030 b7000000 00000000 95000000 00000000 ...............
从这里,我看不出您打算稍后如何检索各个程序以正确加载它们。通常,用户 space 工具从一个部分获取一个程序,并尝试通过 bpf()
系统调用将指令传递给内核来加载它们;在这里,无论您使用什么程序,都可能会尝试同时加载串联的四个程序。
是否有特殊原因让您希望所有程序都以相同的名称放在节中?
我不知道 LLVM 中关于此类事情的警告。我猜不是:人们可能有理由将不同的东西放在一个部分中。这里的案例是 BPF 特有的,我认为人们通常不会尝试将多个程序放在同一部分中。但这只是一个猜测,我可能是错的。
关于您的更新:
我不认为在不同的目标文件中使用相似的节名是个问题。只要您的用户 space 工具能够从目标文件中检索程序并执行重定位,它就应该可以正常工作。无论如何,内核看不到任何节名。它从 attr
参数中获取的是一个指令数组:
struct { /* anonymous struct used by BPF_PROG_LOAD command */
__u32 prog_type; /* one of enum bpf_prog_type */
__u32 insn_cnt;
__aligned_u64 insns;
__aligned_u64 license;
__u32 log_level; /* verbosity level of verifier */
__u32 log_size; /* size of user buffer */
__aligned_u64 log_buf; /* user supplied buffer */
__u32 kern_version; /* checked when prog_type=kprobe */
__u32 prog_flags;
char prog_name[BPF_OBJ_NAME_LEN];
__u32 prog_ifindex; /* ifindex of netdev to prep for */
};
(来自 include/uapi/linux/bpf.h
,注意 insns
属性)。对于尾部调用,您的用户 space 代码还需要创建特定映射,以保存对您要跳转到的程序的引用(更多 bpf()
调用)。但同样,用户 space 有责任从 ELF 文件中提取信息。 libbpf我觉得应该可以正确处理,但是我没试过
要完成的旁注:我不知道你的用例到底是什么,但由于你试图在不同的目标文件中编译你的代码并使用调用,你可能有兴趣现在学习 eBPF支持“函数调用”,即你可以定义几个(非内联)函数,可能在几个 ELF 文件中,并在你的程序中调用它们。更多信息 in the cover letter。同样,到目前为止我还没有时间试验它。
bpf
程序中的每个程序部分是否必须具有唯一的名称?例如,这个程序可以很好地编译 llvm-5.0
:
...
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;
但是,llvm-objdump
只报告了一个节目部分:
$ 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
是否有至少给出警告的编译器选项?
UPDATE - 所以我知道同一个 bpf 文件中提供的部分必须具有唯一的名称。在 bpf 程序驻留在不同的文件中并独立编译的情况下是否如此,以便它们可以加载并相互调用,例如tail calls
?
显然,编译器将同一部分中的所有内容串联起来(我简化了 bpf_main
以使其编译和测试)。
$ readelf -x sockops bpf_prog.o
Hex dump of section 'sockops':
0x00000000 b7000000 01000000 95000000 00000000 ................
0x00000010 b7000000 01000000 95000000 00000000 ................
0x00000020 b7000000 01000000 95000000 00000000 ................
0x00000030 b7000000 00000000 95000000 00000000 ...............
从这里,我看不出您打算稍后如何检索各个程序以正确加载它们。通常,用户 space 工具从一个部分获取一个程序,并尝试通过 bpf()
系统调用将指令传递给内核来加载它们;在这里,无论您使用什么程序,都可能会尝试同时加载串联的四个程序。
是否有特殊原因让您希望所有程序都以相同的名称放在节中?
我不知道 LLVM 中关于此类事情的警告。我猜不是:人们可能有理由将不同的东西放在一个部分中。这里的案例是 BPF 特有的,我认为人们通常不会尝试将多个程序放在同一部分中。但这只是一个猜测,我可能是错的。
关于您的更新:
我不认为在不同的目标文件中使用相似的节名是个问题。只要您的用户 space 工具能够从目标文件中检索程序并执行重定位,它就应该可以正常工作。无论如何,内核看不到任何节名。它从 attr
参数中获取的是一个指令数组:
struct { /* anonymous struct used by BPF_PROG_LOAD command */
__u32 prog_type; /* one of enum bpf_prog_type */
__u32 insn_cnt;
__aligned_u64 insns;
__aligned_u64 license;
__u32 log_level; /* verbosity level of verifier */
__u32 log_size; /* size of user buffer */
__aligned_u64 log_buf; /* user supplied buffer */
__u32 kern_version; /* checked when prog_type=kprobe */
__u32 prog_flags;
char prog_name[BPF_OBJ_NAME_LEN];
__u32 prog_ifindex; /* ifindex of netdev to prep for */
};
(来自 include/uapi/linux/bpf.h
,注意 insns
属性)。对于尾部调用,您的用户 space 代码还需要创建特定映射,以保存对您要跳转到的程序的引用(更多 bpf()
调用)。但同样,用户 space 有责任从 ELF 文件中提取信息。 libbpf我觉得应该可以正确处理,但是我没试过
要完成的旁注:我不知道你的用例到底是什么,但由于你试图在不同的目标文件中编译你的代码并使用调用,你可能有兴趣现在学习 eBPF支持“函数调用”,即你可以定义几个(非内联)函数,可能在几个 ELF 文件中,并在你的程序中调用它们。更多信息 in the cover letter。同样,到目前为止我还没有时间试验它。