BPF Compiler Collection

eBPF(extended Berkekey Packet Filter)という機能を利用したカーネルトレースや操作プログラムを作成するためのツールキット、BCCを試してみました。
OSには、通常のプログラミングが動作するユーザモードと特権をもつプログラムを実行するカーネルモードがあり、BCCを使うとBPFの仕組みを使ってカーネルモードのプログラムをカーネルのコードをビルドすることなく実行できるようです。
Pythonコードの中にC言語のコードを書き、それをコンパイルして実行するようですが、printk関数をはさんでデバッグしていたころに比べてかなり便利な設計になったていると感じました。

参考)
https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu—binary
https://github.com/iovisor/bcc/blob/master/examples/tracing/hello_fields.py
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0690

環境)

$ uname -r
4.15.0-202-generic
$ cat /etc/os-release
NAME=”Ubuntu”
VERSION=”18.04.6 LTS (Bionic Beaver)”
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME=”Ubuntu 18.04.6 LTS”
VERSION_ID=”18.04″
HOME_URL=”https://www.ubuntu.com/”
SUPPORT_URL=”https://help.ubuntu.com/”
BUG_REPORT_URL=”https://bugs.launchpad.net/ubuntu/”
PRIVACY_POLICY_URL=”https://www.ubuntu.com/legal/terms-and-policies/privacy-policy”
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
$ grep BPF /boot/config-uname -r
CONFIG_CGROUP_BPF=y
CONFIG_BPF=y
CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_NETFILTER_XT_MATCH_BPF=m
CONFIG_NET_CLS_BPF=m
CONFIG_NET_ACT_BPF=m
CONFIG_BPF_JIT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_BPF_EVENTS=y
CONFIG_TEST_BPF=m
$ python -V
Python 2.7.17

インストール)

$ sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-keys 4052245BD4284CDD
$ echo “deb https://repo.iovisor.org/apt/$(lsb_release -cs) $(lsb_release -cs) main” | sudo tee /etc/apt/sources.list.d/iovisor.list
$ sudo apt-get update
$ sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)

hello.py

プロセスがcloneされたときに呼び出される処理が書かれています。オリジナルから、bオブジェクトの情報表示と、明示的なタスク、追加項目の表示を加えています。
また以下、exampleにあるhello_work.pyには、”イベント名__関数名”でカーネル内部の任意の関数をフックできるしくみで書かれていますが、ここではget_syscall_fnname(“clone”)という形でかかれています。

プログラムを起動した後、別コンソールでlsコマンド、curlコマンドを実行してみました。

実行結果

$ sudo python hello.py
[‘CGROUP_DEVICE’,
‘CGROUP_SKB’,
‘CGROUP_SOCK’,
‘CGROUP_SOCK_ADDR’,
‘CLOCK_MONOTONIC’,
‘Function’,
‘KPROBE’,
‘LWT_IN’,
‘LWT_OUT’,
‘LWT_XMIT’,
‘PERF_EVENT’,
‘RAW_TRACEPOINT’,
‘SCHED_ACT’,
‘SCHED_CLS’,
‘SK_MSG’,
‘SK_SKB’,
‘SOCKET_FILTER’,
‘SOCK_OPS’,
‘TRACEPOINT’,
‘Table’,
‘XDP’,
‘XDP_ABORTED’,
‘XDP_DROP’,
‘XDP_PASS’,
‘XDP_REDIRECT’,
‘XDP_TX’,
‘__class__’,
‘__delattr__’,
‘__delitem__’,
‘__dict__’,
‘__doc__’,
‘__enter__’,
‘__exit__’,
‘__format__’,
‘__getattribute__’,
‘__getitem__’,
‘__hash__’,
‘__init__’,
‘__iter__’,
‘__len__’,
‘__module__’,
‘__new__’,
‘__reduce__’,
‘__reduce_ex__’,
‘__repr__’,
‘__setattr__’,
‘__setitem__’,
‘__sizeof__’,
‘__str__’,
‘__subclasshook__’,
‘__weakref__’,
‘_add_kprobe_fd’,
‘_add_uprobe_fd’,
‘_attach_perf_event’,
‘_auto_includes’,
‘_bsymcache’,
‘_check_path_symbol’,
‘_check_probe_quota’,
‘_clock_gettime’,
‘_decode_table_type’,
‘_del_kprobe_fd’,
‘_del_uprobe_fd’,
‘_find_file’,
‘_get_uprobe_evname’,
‘_librt’,
‘_probe_repl’,
‘_sym_cache’,
‘_sym_caches’,
‘_syscall_prefixes’,
‘_trace_autoload’,
‘add_module’,
‘attach_kprobe’,
‘attach_kretprobe’,
‘attach_perf_event’,
‘attach_raw_socket’,
‘attach_raw_tracepoint’,
‘attach_tracepoint’,
‘attach_uprobe’,
‘attach_uretprobe’,
‘attach_xdp’,
‘cleanup’,
‘debug’,
‘decode_table’,
‘detach_kprobe’,
‘detach_kprobe_event’,
‘detach_kretprobe’,
‘detach_perf_event’,
‘detach_raw_tracepoint’,
‘detach_tracepoint’,
‘detach_uprobe’,
‘detach_uprobe_event’,
‘detach_uretprobe’,
‘disassemble_func’,
‘donothing’,
‘dump_func’,
‘find_exe’,
‘find_library’,
‘fix_syscall_fnname’,
‘free_bcc_memory’,
‘funcs’,
‘generate_auto_includes’,
‘get_kprobe_functions’,
‘get_syscall_fnname’,
‘get_syscall_prefix’,
‘get_table’,
‘get_tracepoints’,
‘get_user_addresses’,
‘get_user_functions’,
‘get_user_functions_and_addresses’,
‘kprobe_fds’,
‘kprobe_poll’,
‘ksym’,
‘ksymname’,
‘load_func’,
‘load_funcs’,
‘module’,
‘monotonic_time’,
‘num_open_kprobes’,
‘num_open_tracepoints’,
‘num_open_uprobes’,
‘open_perf_events’,
‘perf_buffer_poll’,
‘perf_buffers’,
‘raw_tracepoint_fds’,
‘remove_xdp’,
‘str2ctype’,
‘support_raw_tracepoint’,
‘sym’,
‘tables’,
‘timespec’,
‘trace_fields’,
‘trace_open’,
‘trace_print’,
‘trace_readline’,
‘tracefile’,
‘tracepoint_exists’,
‘tracepoint_fds’,
‘uprobe_fds’]
{‘debug’: 0,
‘funcs’: {‘hello’: },
‘kprobe_fds’: {‘p_sys_clone’: 4},
‘module’: 94590567723712,
‘open_perf_events’: {},
‘perf_buffers’: {},
‘raw_tracepoint_fds’: {},
‘tables’: {},
‘tracefile’: None,
‘tracepoint_fds’: {},
‘uprobe_fds’: {}}
TIME(s) COMM PID MESSAGE
3859.149581000 bash 1827 Hello!: bash /…. 0
3861.768011000 bash 1827 Hello!: bash /…. 0
3861.773422000 curl 3930 Hello!: curl /…. 1
3865.956510000 bash 1827 Hello!: bash /…. 0
3865.962982000 curl 3932 Hello!: curl /…. 1

eBPFは、クラウドサービスでよく使われるコンテナ中通信(CNI:Container Network Interface)を実現するCiliumで使われているようです。
「CNIのCiliumについて調べてみた」
https://blog.framinal.life/entry/2021/02/20/222728
このあたり、また掘り下げて調べたいと思っています。

About

Categories: 未分類 タグ: , ,