学习eBPF遇到的问题及解决方法
1. 安装bcc工具包
使用如下指令安装bcc工具包
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
echo "deb https://repo.iovisor.org/apt/xenial xenial main" | sudo tee /etc/apt/sources.list.d/iovisor.list
sudo apt-get update
sudo apt-get install -y bcc-tools libbcc-examples linux-headers-$(uname -r)
export PATH=$PATH:/usr/share/bcc/tools
当执行“sudo apt-get install -y bcc-tools libbcc-examples linux-headers-$(uname -r)”时,出现了如下错误,
***
有一些软件包无法被安装。如果您用的时unstable发行版,这也许是因为系统无法达到您要求的状态造成的。该版本中可能会有一些您需要的软件包尚未被创建或是它们已被从信道(Incoming)目录移出:
下列软件包有为满足的依赖关系
bcc-tools : 依赖: python-bcc (= 0.10.0-1) 但是它将不会被安装
E:无法修正错误,因为您要求的某些软件包保持现状,就是他们破坏了软件包间的以来关系
***
解决方法:
修改如下信息,按照下面两幅图进行勾选:


选择完毕关闭后会更新缓存,更新完毕后,再次执行上述命令,安装就可以正常进行了。
2. 运行example时,出现了如下错误:
./hello_world.py
Traceback (most recent call last):
File "./hello_world.py", line 9, in
from bcc import BPF
File "/usr/lib/python2.7/dist-packages/bcc/__init__.py", line 27, in
from .libbcc import lib, bcc_symbol, bcc_symbol_option, bcc_stacktrace_build_id, _SYM_CB_TYPE
File "/usr/lib/python2.7/dist-packages/bcc/libbcc.py", line 17, in
lib = ct.CDLL("libbcc.so.0", use_errno=True)
File "/usr/lib/python2.7/ctypes/__init__.py", line 366, in __init__
self._handle = _dlopen(self._name, mode)
OSError: libtinfo.so.5: cannot open shared object file: No such file or directory
解决方法:
sudo apt-get install libtinfo5
3. 接着运行,提示如下错误:
***
3 warnings generated.
bpf: Failed to load program: Operation not permitted
***
解决方法:
sudo /hello_world.py
4. 继续运行,提示如下错误:

解决方法:
python默认版本不对,需要更新:
ln [参数] [源文件或目录] [目标文件或目录]
sudo ln -s python3 python
reboot now
继续运行,搞定:

5. 编译系统内核中的bpf例程时,出现了如下问题:
readelf:错误: Missing knowledge of 32-bit reloc types used in DWARF sections of machine number 247

解决方法:
使用llvm_readelf替换readelf
修改前:

修改后:

修改完毕后,再次启动编译,可能会有如下问题:

解决方法:
这是因为没有安装llvm-readelf或者llvm-readelf路径不对导致,安装即可,安装可以参考:
什么是LLVM,LLVM如何配置安装-华为云:https://www.huaweicloud.com/zhishi/LLVM.html
安装完毕后重新编译,问题解决:

安装LLVM&CLANG 7.0.1的方法如下:
curl -LO http://releases.llvm.org/7.0.1/llvm-7.0.1.src.tar.xz
curl -LO http://releases.llvm.org/7.0.1/cfe-7.0.1.src.tar.xz
tar -xf cfe-7.0.1.src.tar.xz
tar -xf llvm-7.0.1.src.tar.xz
mkdir clang-build
mkdir llvm-build
cd llvm-build
cmake3 -G "Unix Makefiles" -DLLVM_TARGETS_TO_BUILD="BPF;X86" -DCMAKE_BUILD_TYPE=Release ../llvm-7.0.1.src
make
sudo make install
cd ../clang-build
cmake3 -G "Unix Makefiles" -DLLVM_TARGETS_TO_BUILD="BPF;X86" -DCMAKE_BUILD_TYPE=Release ../cfe-7.0.1.src
make
sudo make install
cd ..
在编译llvm和clang时,会出现CMake错误:No CMAKE_CXX_COMPILER could be found.
解决方法:
sudo apt-get update
sudo apt-get install -y build-essential
llvm的下载路径:https://github.com/llvm/llvm-project/releases/tag/llvmorg-15.0.0
选择最下面的source code,下载速度较快,但是编译有的会出错,一般使用正式release版本:

正式Release版本截图如下,可以使用IDM或者迅雷下载,IDM更好用;


编译llvm的11.0.0rc6版本时,会有报错“error: ‘numeric_limits’ is not a member of ‘std”,解决方法,在对应报错的文件中包含“#include
在使用vscode软件时,ubuntun软件会出现如下错误:
Unable to download updates from extensions.gnome.org
解决方法:
sudo add-apt-repository ppa:gnome-shell-extensions/ppa
sudo apt-get update
sudo apt-get install gnome-shell-extensions
bpf程序编译过程:
编译指令:clang -O2 -Wall -target bpf -c hello_kern.c -o hello_kern.o
hello_kern.c的内容如下:
#define __BPF_FUNC_MAPPER(FN) \
FN(unspec), \
FN(map_lookup_elem), \
FN(map_update_elem), \
FN(map_delete_elem), \
FN(probe_read), \
FN(ktime_get_ns), \
FN(trace_printk), \
FN(get_prandom_u32), \
FN(get_smp_processor_id), \
FN(skb_store_bytes), \
FN(l3_csum_replace), \
FN(l4_csum_replace), \
FN(tail_call), \
FN(clone_redirect), \
FN(get_current_pid_tgid), \
FN(get_current_uid_gid), \
FN(get_current_comm), \
FN(get_cgroup_classid), \
FN(skb_vlan_push), \
FN(skb_vlan_pop), \
FN(skb_get_tunnel_key), \
FN(skb_set_tunnel_key), \
FN(perf_event_read), \
FN(redirect), \
FN(get_route_realm), \
FN(perf_event_output), \
FN(skb_load_bytes), \
FN(get_stackid), \
FN(csum_diff), \
FN(skb_get_tunnel_opt), \
FN(skb_set_tunnel_opt), \
FN(skb_change_proto), \
FN(skb_change_type), \
FN(skb_under_cgroup), \
FN(get_hash_recalc), \
FN(get_current_task), \
FN(probe_write_user), \
FN(current_task_under_cgroup), \
FN(skb_change_tail), \
FN(skb_pull_data), \
FN(csum_update), \
FN(set_hash_invalid), \
FN(get_numa_node_id), \
FN(skb_change_head), \
FN(xdp_adjust_head), \
FN(probe_read_str), \
FN(get_socket_cookie), \
FN(get_socket_uid), \
FN(set_hash), \
FN(setsockopt), \
FN(skb_adjust_room), \
FN(redirect_map), \
FN(sk_redirect_map), \
FN(sock_map_update), \
FN(xdp_adjust_meta), \
FN(perf_event_read_value), \
FN(perf_prog_read_value), \
FN(getsockopt), \
FN(override_return), \
FN(sock_ops_cb_flags_set), \
FN(msg_redirect_map), \
FN(msg_apply_bytes), \
FN(msg_cork_bytes), \
FN(msg_pull_data), \
FN(bind), \
FN(xdp_adjust_tail), \
FN(skb_get_xfrm_state), \
FN(get_stack), \
FN(skb_load_bytes_relative), \
FN(fib_lookup), \
FN(sock_hash_update), \
FN(msg_redirect_hash), \
FN(sk_redirect_hash), \
FN(lwt_push_encap), \
FN(lwt_seg6_store_bytes), \
FN(lwt_seg6_adjust_srh), \
FN(lwt_seg6_action), \
FN(rc_repeat), \
FN(rc_keydown), \
FN(skb_cgroup_id), \
FN(get_current_cgroup_id), \
FN(get_local_storage), \
FN(sk_select_reuseport), \
FN(skb_ancestor_cgroup_id), \
FN(sk_lookup_tcp), \
FN(sk_lookup_udp), \
FN(sk_release), \
FN(map_push_elem), \
FN(map_pop_elem), \
FN(map_peek_elem), \
FN(msg_push_data), \
FN(msg_pop_data), \
FN(rc_pointer_rel), \
FN(spin_lock), \
FN(spin_unlock), \
FN(sk_fullsock), \
FN(tcp_sock), \
FN(skb_ecn_set_ce), \
FN(get_listener_sock), \
FN(skc_lookup_tcp), \
FN(tcp_check_syncookie), \
FN(sysctl_get_name), \
FN(sysctl_get_current_value), \
FN(sysctl_get_new_value), \
FN(sysctl_set_new_value), \
FN(strtol), \
FN(strtoul), \
FN(sk_storage_get), \
FN(sk_storage_delete), \
FN(send_signal), \
FN(tcp_gen_syncookie),
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
*/
#define __BPF_ENUM_FN(x) BPF_FUNC_ ## x
enum bpf_func_id {
__BPF_FUNC_MAPPER(__BPF_ENUM_FN)
__BPF_FUNC_MAX_ID,
};
#undef __BPF_ENUM_FN
#define SEC(NAME) __attribute__((section (NAME), used))
static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
(void*) BPF_FUNC_trace_printk;
SEC("kprobe/sys_write")
int bpf_prog(void *ctx)
{
char msg[] = "hello world!\n";
bpf_trace_printk(msg, sizeof(msg));
return 0;
}
char _lincense[] SEC("license") = "GPL";
同样也可以分开编译:
1. 生成IR文件(扩展名为ll):clang -O2 -Wall -emit-llvm -S hello_kern.c
2. 生成目标文件(扩展名为o):llc hello_kern.ll -march=bpf -filetype=obj -o hello_kern.o
总结:
eBPF的编译需要如下步骤:
1. 下载与系统内核一致的内核代码;
2. 将内核代码解压到/usr/src中;
3. 安装clang和llvm,安装后找不到llvm-readelf时,可以下载llvm的源码,编译安装,编译方法可以参考上述提供的链接:什么是LLVM,LLVM如何配置安装
4. 使用命令:sudo make defconfig,生成配置文件;
5. 使用命令:sudo make headers_install,安装头文件;
6. 使用命令:sudo make M=sample/bpf完成系统自带例程的编译;
注意:过程中遇到依赖的库没有安装,则使用命令:sudo apt-get install ****进行安装即可;
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
