eXpress Data Path / Cilium

BPF関連のテストはこれまでトレーシングが主でしたが、ここでは実用的なものとして、XDP(eXpress Data Path)を使ったパケットフィルタリングを試してみました。
BPF開発のライブラリはいろいろな形がありますが、今回は、Go言語でコードを生成するタイプのものになります。

参考)
https://github.com/cilium/ebpf/tree/master/examples/xdp

環境)
Ubuntu 22.04

n@n10:~$ uname -r
5.15.0-67-generic

n@n10:~$ grep BPF /boot/config-5.15.0-67-generic
CONFIG_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_ARCH_WANT_DEFAULT_BPF_JIT=y
# BPF subsystem
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
CONFIG_BPF_UNPRIV_DEFAULT_OFF=y
# CONFIG_BPF_PRELOAD is not set
CONFIG_BPF_LSM=y
# end of BPF subsystem
CONFIG_CGROUP_BPF=y
CONFIG_IPV6_SEG6_BPF=y
CONFIG_NETFILTER_XT_MATCH_BPF=m
CONFIG_BPFILTER=y
CONFIG_BPFILTER_UMH=m
CONFIG_NET_CLS_BPF=m
CONFIG_NET_ACT_BPF=m
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_BPF_EVENTS=y
CONFIG_BPF_KPROBE_OVERRIDE=y
CONFIG_TEST_BPF=m

n@n10:~$ grep XDP /boot/config-5.15.0-67-generic
CONFIG_XDP_SOCKETS=y
CONFIG_XDP_SOCKETS_DIAG=m
CONFIG_SENSORS_XDPE122=m

n@n10:~$ go version
go version go1.18.1 linux/amd64

xdp.c(DROPを加え変更)

ビルド

n@n10:~/ebpf/examples$ sudo make -C ../
[sudo] password for n:
make: Entering directory ‘/home/n/ebpf’
docker run –rm –user “1000:1000” \
-v “/home/n/ebpf”:/ebpf -w /ebpf –env MAKEFLAGS \
–env CFLAGS=”-fdebug-prefix-map=/ebpf=.” \
–env HOME=”/tmp” \
“ghcr.io/cilium/ebpf-builder:1666886595” \
make all
make: Entering directory ‘/ebpf’
find . -type f -name “*.c” | xargs clang-format -i
go generate ./…
go: downloading golang.org/x/sys v0.2.0
Compiled /ebpf/cmd/bpf2go/test/test_bpfel.o
Stripped /ebpf/cmd/bpf2go/test/test_bpfel.o
Wrote /ebpf/cmd/bpf2go/test/test_bpfel.go
Compiled /ebpf/cmd/bpf2go/test/test_bpfeb.o
Stripped /ebpf/cmd/bpf2go/test/test_bpfeb.o
….
Compiled /ebpf/examples/xdp/bpf_bpfel.o
Stripped /ebpf/examples/xdp/bpf_bpfel.o
Wrote /ebpf/examples/xdp/bpf_bpfel.go
Compiled /ebpf/examples/xdp/bpf_bpfeb.o
Stripped /ebpf/examples/xdp/bpf_bpfeb.o
Wrote /ebpf/examples/xdp/bpf_bpfeb.go
enum AdjRoomMode
enum AttachType
enum Cmd
enum FunctionId
….
attr ProgGetNextId
attr ProgLoad
attr ProgQuery
attr ProgRun
attr RawTracepointOpen
ln -srf testdata/loader-clang-14-el.elf testdata/loader-el.elf
ln -srf testdata/loader-clang-14-eb.elf testdata/loader-eb.elf
make: Leaving directory ‘/ebpf’
make: Leaving directory ‘/home/n/ebpf’

docker imageを使ってビルドしています。
xdp.cと同じフォルダにあるmain.goには、下記の記述があり、generatorにより、bpf_bpfeb.go, bpf_bpfel.goが生成されます。

// $BPF_CLANG and $BPF_CFLAGS are set by the Makefile.
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf xdp.c — -I../headers

ebpf/cmd/bpf2go/
https://github.com/cilium/ebpf/tree/master/cmd/bpf2go

このような手の込んだことをして、カーネルモジュールを動かすしくみを作っています。


実行

n@n10:~/ebpf/examples$ go run -exec sudo ./xdp enp0s3
2023/03/06 06:06:13 Attached XDP program to iface “enp0s3” (index 2)
2023/03/06 06:06:13 Press Ctrl-C to exit and remove the program
2023/03/06 06:06:14 Map contents:
192.168.1.228 => 2
2023/03/06 06:06:15 Map contents:
192.168.1.228 => 3
2023/03/06 06:06:16 Map contents:
192.168.1.228 => 4
….

テスト内容
192.168.1.228 (host)
192.168.1.217
上二つからxdpプログラムを実行している下記にcurlコマンドを実行します。
192.168.1.172

printk出力の確認

上記出力からはわかりにくいですが、xdpプログラムを実行しているとき、ホスト以外からはcurlコマンドのレスポンスがないことを確認しています。コードのコメントをはずすとpingパケロットのフィルタリングも確認できます。

ただテストをホストからのSSH接続していて接続が不安定になったりしました。フィルタリングしていないとはいえ、デフォルトDropのロジックは、弊害があるかもしれません。要調査です。

カーネルプログラムでは、コードをコメントしただけでエラーが発生するなど、通常のCプログラムではないようなことが起きました。(未定義という単純なものではなく、invalid indirect read from stack offなどといったものなど)
このあたり関連する部分を注意深くコーディングする必要があるようです。