Linux eBPFをネットワーク機能まわりで使う使い方について。
BPF の現在Kawai, Hiroaki
View Slide
cBPF, eBPF● BPF = Berkeley Packet Filter● cBPF = Classic BPF– eBPF と区別するとき● tcpdump/libpcap– フィルタ式– nfbpf_compile[email protected]:~# tcpdump -d arp(000) ldh [12](001) jeq #0x806 jt 2 jf 3(002) ret #262144(003) ret #0[email protected]:~# tcpdump -dd arp{ 0x28, 0, 0, 0x0000000c },{ 0x15, 0, 1, 0x00000806 },{ 0x6, 0, 0, 0x00040000 },{ 0x6, 0, 0, 0x00000000 },[email protected]:~# tcpdump -ddd arp440 0 0 1221 0 1 20546 0 0 2621446 0 0 0
cBPF● フィルタ式– pcap_compile● C macro (linux/filter.h)– ex: BPF_STMT(BPF_LD | BPF_IMM, 1)● libseccomp– ex: seccomp_rule_add(SCMP_ACT_ALLOW,SCMP_SYS(close), 0);
eBPF● eBPF = 命令セットとして整備(別物)– ISA (Instruction Set Architecture)– 64bit(x86_64, ARM64と整ってきたので)● JIT in kernel– CPU 命令セットにマッピング– cBPF も eBPF 経由で JIT されるhttps://events.linuxfoundation.org/sites/events/files/slides/ebpf_on_the_mainframe_lcon_2015.pdf
eBPF compiler● フィルタ式 = DSL から C 言語(限定版)へ● clang でコンパイル– eBPF / ELF オブジェクトファイル– tc はこれを使ったりするclang -O2 -emit-llvm -c bpf.c -o - \| llc -march=bpf -filetype=obj -o bpf.oRef: samples/bpf/README.rst
LLVM_P4● P4実行環境としてのeBPF– CではなくP4で# p4llvm switch1.p4# opt –O2 switch1.ll –o switch1.ll# llc –march=bpf –filetype=obj –o switch1.o switch1.ll# tc qdisc add dev eth3 ingress# tc filter add dev eth3 parent ffff: bpf obj switch1.o exp /tmp/p4clihttps://schd.ws/hosted_files/2016p4workshop/1d/Intel%20Fastabend-P4%20on%20the%20Edge.pdf
実行環境● Linux kernel– socket filter– seccomp2– tc filter&action, iptables bpf module– tracing, perf– cgroup● Userland– iovisor/ubpf (Big switch)Chrome : packet=syscall引数tcpdumplibpcapiovisor
Load into kernel● 設定方法– cBPF Bytecode バイト列を設定する● cBPF (w/ extension) Bytecode は内部で eBPF 化– eBPF/ELF ファイルから読み込む● Persistent (pinned) bpf object– Kernel /sys/fs/bpf で保持できる– “FD” が出てきたらこれを指していることも
networking● socket : ingress only, cBPF & eBPF● tc : ingress & egress, cBPF & eBPF● iptables(netfilter) xt_bpf : socket 相当● xdp : ingress only, eBPF● Lwt : pinned bpf, eBPF新しいkernelでないとダメなやつも多々…
Linux kernel● setsockopt SOL_SOCKET SO_ATTACH_BPF– SO_ATTACH_FILTER : cBPF● rtnetlink– struct tcmsg/TCA_KIND=”bpf”, TCA_ACT_BPF– stcuct ifinfomsg/IFLA_XDP– struct rtmsg/LWT_BPF_IN, LWT_BPF_OUT, …● bpf(2) : fd 使う
bpf_prog_type● in-kernel での制限チェックで使われる● Packet data にアクセスできるか等● きちんと完了するプログラムか等● BPF fd の属性値として保持される● linux/bpf.h– BPF_PROG_TYPE_*– fdinfo (4.8~)SOCKET_FILTERKPROBESCHED_CLS, SCHED_ACTTRACEPOINTXDPPERF_EVENTCGROUP_SKB, CGROUP_SOCKLWT_IN, LWT_OUT, LWT_XMIT
eBPF in C● 引数と返値– tc : struct __sk_buff● filter classifier と filter action で返値の意味が異なる– xdp : struct xdp_md : sk_buff に似せてある● BPF MAP– パケット数えたり– ルールを保持したり
BPF MAP● 種類– BPF_TABLE●BPF_HASH●BPF_HISTOGRAM●BPF_STACK_TRACE– BPF_TABLE_PUBLIC– BPF_PERF_OUTPUT– BPF_PERF_ARRAY[email protected]:/proc/3463/fd# ls -ltotal 0lrwx------ 1 root root 64 Dec 22 02:21 0 -> /dev/pts/17lrwx------ 1 root root 64 Dec 22 02:21 1 -> /dev/pts/17lrwx------ 1 root root 64 Dec 22 02:21 10 -> anon_inode:bpf-maplrwx------ 1 root root 64 Dec 22 02:21 11 -> anon_inode:bpf-maplrwx------ 1 root root 64 Dec 22 02:21 12 -> anon_inode:bpf-proglrwx------ 1 root root 64 Dec 22 02:21 13 -> anon_inode:bpf-proglrwx------ 1 root root 64 Dec 22 02:21 14 -> anon_inode:bpf-proglrwx------ 1 root root 64 Dec 22 02:21 15 -> anon_inode:bpf-proglrwx------ 1 root root 64 Dec 22 02:21 2 -> /dev/pts/17lr-x------ 1 root root 64 Dec 22 02:21 3 -> /dev/urandomlr-x------ 1 root root 64 Dec 22 02:21 4 -> pipe:[35440]l-wx------ 1 root root 64 Dec 22 02:21 5 -> pipe:[35440]lrwx------ 1 root root 64 Dec 22 02:21 6 -> socket:[35441]lr-x------ 1 root root 64 Dec 22 02:21 7 -> pipe:[35442]l-wx------ 1 root root 64 Dec 22 02:21 8 -> pipe:[35442]lrwx------ 1 root root 64 Dec 22 02:21 9 -> socket:[35443]
Writing eBPF● iovisor/bcc 使う(依存は増える)– BPF_MAP_GET_NEXT_KEY 無かったりとかもある● tc filter classifier 使うのが現実的な選択● C言語はコンパイラのココロを読みながら書く– prog_load失敗する=ココロが通じなかったとき● bpf_trace_printk– cat /sys/kernel/debug/tracing/trace_pipe
Tools● ubpf-disassembler (ubpf)– eBPF● bpfc (netsniff-ng)– cBPF (w/ extension)● bpf_dbg (kernel)– eBPF