简单的 eBPF 操作不会对 tc 生效

Simple eBPF action not taking effect with tc

我从 samples/bpf/pare_simple.c(来自 Linux 内核树)编译了 BPF 示例,并做了非常简单的更改:

SEC("simple")
int handle_ingress(struct __sk_buff *skb)
{
   return TC_ACT_SHOT;
}

所以我希望丢弃任何数据包。我是这样安装的:

这发生在 Ubuntu 16.04.3 LTS 上,内核 4.4.0-98,llvm 和从软件包安装的 3.8 版 clang,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

所以它似乎安装成功,但是这个 filter/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
                   ^^^^^^^^^^^^^

tc bpf filter bpf help 的简短帮助提到了这个标志,但如果我没记错的话,目前还没有进入 tc-bpf(8) 手册页。

那么,这个标志是做什么用的?

eBPF 程序可以通过两种方式附加到 tc:作为 actions,或作为 classifiers。附加有tc filter add 的分类器应该用于过滤数据包,默认情况下不应用操作。这意味着它们的 return 值具有以下含义(来自 man tc-bpf):

0 , denotes a mismatch

-1 , denotes the default classid configured from the command line

else , everything else will override the default classid to provide a facility for non-linear matching

另一方面,tc action add 附带的操作可以丢弃、镜像或对数据包执行其他操作,但它们不应该实际过滤它们。

因为 eBPF 比 tc 的传统操作和过滤器更灵活,您实际上可以同时执行这两项操作,过滤数据包(即识别此数据包)并对它执行操作。为了反映这种灵活性,添加了 direct-actionda 标志(对于内核 4.4 或更新版本,具有匹配的 iproute2 包)。它告诉内核将 actionsTC_ACT_SHOTTC_ACT_OK 等)的 return 值用于 classifiers。这就是你在这里需要的 return TC_ACT_SHOT 以内核理解你想要丢弃数据包的方式。

如果我没记错的话,我们使用这个标志而不是仅仅为操作删除过滤器的原因是你无论如何都需要一个带有 tc 的过滤器来附加你的操作? (待确认)。因此,使用 direct-action 标志,您不必同时附加一个过滤器和一个操作,过滤器可以执行这两种操作。这应该是使用 tc 进行 eBPF 编程的首选方式。