ローファイ日記

出てくるコード片、ぼくが書いたものは断りがない場合 MIT License としています http://udzura.mit-license.org/

eBPF でイベントが起こったプロセスの cgroup IDを取るには

bpftrace には cgroup という変数があって、イベントが起こったプロセスの cgroup ID(後述しますが、?な数字です)を取得できます。

$ bpftrace -e 'uretprobe:/bin/bash:readline { printf("input(%d@%d) = %s\n", pid, cgroup, str(retval)); }'
Attaching 1 probe...

input(16277@2055) =
input(16277@2055) = echo $$ > /sys/fs/cgroup/unified/sample100/cgroup.procs # <= ここで変更
input(16277@2139) = ls -l

これはちなみに、カーネルのバージョンが古いとこういうエラーになります。

stdin:1:38-46: ERROR: BPF_FUNC_get_current_cgroup_id is not available for your kernel version

使う場合、Ubuntu Bionicあたりはカーネル5.0.0を入れられるので、それを入れてbpftraceを自分でビルドすればOKです...

と言いたいところですが、なぜかビルドで参照するヘッダが入っている linux-libc-dev というパッケージがカーネル 4.4 相当のままなので、先のバージョンのディストロから当該のものを個別に入れます。それでいいのかな。最初からDiscoあたりで試すのなら問題はないはずです。

wget http://kr.archive.ubuntu.com/ubuntu/pool/main/l/linux/linux-libc-dev_5.0.0-29.31_amd64.deb
dpkg -i linux-libc-dev_5.0.0-29.31_amd64.deb

こういうコマンドを打って get_current_cgroup_id が見つかれば大丈夫です。

$ grep 'FN(' /usr/include/linux/bpf.h | grep cgroup
        FN(get_cgroup_classid),         \
        FN(skb_under_cgroup),           \
        FN(current_task_under_cgroup),  \
        FN(skb_cgroup_id),              \
        FN(get_current_cgroup_id),      \
        FN(skb_ancestor_cgroup_id),     \

しかし、この「プロセスの cgroup ID」だと思われる値がなんなのか、ここから path に変換するにはどうすればいいのか、の情報がなく、知見があれば嬉しいです。

ちなみに tracepoint の tracepoint:cgroup:cgroup_mkdir などで取れる cgroup ID とは違うものです。なんでやねん...。

root@ubuntu-bionic:~# cat /sys/kernel/debug/tracing/events/cgroup/cgroup_mkdir/format 
name: cgroup_mkdir
ID: 426
format:
        field:unsigned short common_type;       offset:0;       size:2; signed:0;
        field:unsigned char common_flags;       offset:2;       size:1; signed:0;
        field:unsigned char common_preempt_count;       offset:3;       size:1; signed:0;
        field:int common_pid;   offset:4;       size:4; signed:1;

        field:int root; offset:8;       size:4; signed:1;
        field:int id;   offset:12;      size:4; signed:1;
        field:int level;        offset:16;      size:4; signed:1;
        field:__data_loc char[] path;   offset:20;      size:4; signed:1;

print fmt: "root=%d id=%d level=%d path=%s", REC->root, REC->id, REC->level, __get_str(path)
root@ubuntu-bionic:~# echo 1 > /sys/kernel/debug/tracing/events/cgroup/cgroup_mkdir/enable 
root@ubuntu-bionic:~# mkdir /sys/fs/cgroup/unified/sample100
root@ubuntu-bionic:~# cat  /sys/kernel/debug/tracing/trace                                                                                               
# tracer: nop                                                                                                                                            
#                                                                                                                                                       
# entries-in-buffer/entries-written: 10/10   #P:4                                                                                                        
#                                                                                                                                                       
#                              _-----=> irqs-off                                                                                                         
#                             / _----=> need-resched                                                                                                    
#                            | / _---=> hardirq/softirq                                                                                                  
#                            || / _--=> preempt-depth                                                                                                    
#                            ||| /     delay                                                                                                             
#           TASK-PID   CPU#  ||||    TIMESTAMP  FUNCTION                                                                                                 
#              | |       |   ||||       |         |                                                                                                      
         systemd-1     [001] .... 11267.304951: cgroup_mkdir: root=0 id=93 level=2 path=/system.slice/phpsessionclean.service                            
         systemd-1     [001] .... 11267.304983: cgroup_mkdir: root=1 id=44 level=2 path=/system.slice/phpsessionclean.service                           
         systemd-1     [001] .... 11267.305028: cgroup_mkdir: root=4 id=7 level=2 path=/system.slice/phpsessionclean.service                            
         systemd-1     [001] .... 11267.305072: cgroup_mkdir: root=7 id=7 level=2 path=/system.slice/phpsessionclean.service                             
         systemd-1     [001] .... 11267.305201: cgroup_mkdir: root=5 id=22 level=2 path=/system.slice/phpsessionclean.service                           
         systemd-1     [001] .... 11267.305228: cgroup_mkdir: root=12 id=7 level=2 path=/system.slice/phpsessionclean.service                           
         systemd-1     [001] .... 11267.305249: cgroup_mkdir: root=3 id=43 level=2 path=/system.slice/phpsessionclean.service                            
           mkdir-17339 [003] .... 11269.994534: cgroup_mkdir: root=0 id=93 level=1 path=/sample100                                                       
           mkdir-17340 [000] .... 11271.699314: cgroup_mkdir: root=0 id=94 level=1 path=/sample200                                                       
           mkdir-17341 [002] .... 11273.392368: cgroup_mkdir: root=0 id=95 level=1 path=/sample300                                                      

この情報だけなら /sample100 というcgroupのIDは 93 のはず。しかし。。。

$ bpftrace -e 'uretprobe:/bin/bash:readline { printf("input(%d@%d) = %s\n", pid, cgroup, str(retval)); }'
Attaching 1 probe...

input(16277@2055) =
input(16277@2055) = echo $$ > /sys/fs/cgroup/unified/sample100/cgroup.procs # <= ここで /sample100 に所属
input(16277@2139) = ls -l
# 2139 とは???

桁が小さいから inode とかでもない気がするんですが。。

周辺のカーネルのドキュメントやソースコードなどを追う必要がありそう。


そしてカーネル 5.0 だと、例の PSI も使えるので、コンテナモニタリング周りで色々道具が増えそうですね。楽しそう。

udzura.hatenablog.jp