Mar*_*ark 4 linux-kernel bpf ebpf
samples/bpf/pare_simple.c我通过非常简单的更改(来自 Linux 内核树)编译了 BPF 示例:
SEC("simple")
int handle_ingress(struct __sk_buff *skb)
{
return TC_ACT_SHOT;
}
Run Code Online (Sandbox Code Playgroud)
所以我希望丢弃任何数据包。我安装它如下:
这种情况发生在 Ubuntu 16.04.3 LTS 上,内核为 4.4.0-98,从软件包安装了 llvm 和 clang 版本 3.8,iproute2 是来自 github 的最新版本。
$ tc qdisc add dev eth0 clsact
$ tc filter add dev eth0 ingress bpf \
object-file ./net-next.git/samples/bpf/parse_simple.o \
section simple verbose
Prog section 'simple' loaded (5)!
- Type: 3
- Instructions: 2 (0 over limit)
- License: GPL
Verifier analysis:
0: (b7) r0 = 2
1: (95) exit
processed 2 insns, stack depth 0
Run Code Online (Sandbox Code Playgroud)
所以看起来它安装成功,但是这个过滤器/ebpf 不会丢弃数据包,我在eth0接口上生成入口流量,例如 ICMP,并且它继续传递。我究竟做错了什么?
TL;DR:您应该direct-action向命令添加标志tc filter,如下所示
tc filter add dev eth0 ingress bpf \
object-file ./net-next.git/samples/bpf/parse_simple.o \
section simple direct-action verbose
^^^^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
简短的帮助提到了这个标志,但如果我没记错的话,目前还tc bpf filter bpf help没有进入手册页。tc-bpf(8)
那么,这个标志有什么用呢?
eBPF 程序可以通过两种方式与 tc 附加:作为actions,或作为classifiers。附加有 的分类器tc filter add应该用于过滤数据包,并且默认情况下不应用操作。这意味着它们的返回值具有以下含义(来自man tc-bpf):
0 , 表示不匹配
-1 ,表示从命令行配置的默认classid
else ,其他所有内容都将覆盖默认的 classid 以提供非线性匹配的设施
tc action add另一方面,附加有 的操作可以丢弃或镜像数据包或对数据包执行其他操作,但它们不应该实际过滤它们。
因为 eBPF 比 tc 的传统操作和过滤器更灵活,所以您实际上可以同时执行这两项操作,过滤数据包(即识别该数据包)并对其执行操作。为了反映这种灵活性,添加了direct-action, 或da标志(对于内核 4.4 或更高版本,具有匹配的 iproute2 包)。它告诉内核使用分类器的操作(TC_ACT_SHOT、TC_ACT_OK等)的返回值。这就是您需要以内核理解您想要丢弃数据包的方式返回的内容。TC_ACT_SHOT
如果我没记错的话,我们使用此标志而不是仅仅删除操作过滤器的原因是您无论如何都需要一个带有 tc 的过滤器来将您的操作附加到?(待确认)。因此,使用该direct-action标志,您不必同时附加一个过滤器和一个操作,过滤器可以执行这两种操作。这应该是使用 tc 进行 eBPF 编程的首选方法。