bpf link 的引入是为了解决 bpf prog attachment 持久化的问题,并由此引入了 bpf link fd。
在引入了 bpf link 之后,常用的 bpf prog attachment 都实现了对应的 bpf link,比如 TRACING, XDP, CGROUP, PERF_EVENT 等。
其实,在将 bpf link 引入内核之前,libbpf 便已经引入了 bpf link 的概念。
本文将基于 kernel 6.9 版本的代码来讲解 bpf link 的实现原理。
bpf link 创建过程
以 XDP bpf prog 为例,创建 bpf link 的过程如下:
1
2
3
4
|
SYSCALL_DEFINE3(bpf) // ${KERNEL}/kernel/bpf/syscall.c
|-->__sys_bpf()
|-->link_create()
|-->bpf_xdp_link_attach() // ${KERNEL}/net/core/dev.c
|
其中 bpf_xdp_link_attach()
是 XDP bpf prog 的 attachment 函数,其源代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
// ${KERNEL}/net/core/dev.c
int bpf_xdp_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
{
struct net *net = current->nsproxy->net_ns;
struct bpf_link_primer link_primer;
struct netlink_ext_ack extack = {};
struct bpf_xdp_link *link;
struct net_device *dev;
int err, fd;
rtnl_lock();
// 通过 ifindex 找到对应的 net_device
dev = dev_get_by_index(net, attr->link_create.target_ifindex);
if (!dev) {
rtnl_unlock();
return -EINVAL;
}
// 创建 bpf link 使用的内存
link = kzalloc(sizeof(*link), GFP_USER);
if (!link) {
err = -ENOMEM;
goto unlock;
}
// 初始化 bpf link
bpf_link_init(&link->link, BPF_LINK_TYPE_XDP, &bpf_xdp_link_lops, prog);
link->dev = dev;
link->flags = attr->link_create.flags;
// 分配 fd, ID,和创建一个匿名 file
err = bpf_link_prime(&link->link, &link_primer);
if (err) {
kfree(link);
goto unlock;
}
// XDP bpf prog 的 attach 过程
err = dev_xdp_attach_link(dev, &extack, link);
rtnl_unlock();
if (err) {
link->dev = NULL;
bpf_link_cleanup(&link_primer);
trace_bpf_xdp_link_attach_failed(extack._msg);
goto out_put_dev;
}
// 将 fd 和 file 关联起来,后面便能通过 fd 来找到对应的 link 了
fd = bpf_link_settle(&link_primer);
/* link itself doesn't hold dev's refcnt to not complicate shutdown */
dev_put(dev);
return fd;
unlock:
rtnl_unlock();
out_put_dev:
dev_put(dev);
return err;
}
|
由 bpf_xdp_link_attach()
可以看出,创建 bpf link 的过程主要包括以下几个步骤:
- 创建 bpf link 使用的内存。
- 初始化 bpf link。
- 分配 fd, ID,和创建一个匿名 file,缓存到 bpf prime 里。
- bpf prog 的 attach 过程。
- 将 ID 转给 bpf link,并将 fd 和 file 关联起来。
bpf link 更新过程
更新 XDP bpf prog 的实现过程如下:
1
2
3
4
|
SYSCALL_DEFINE3(bpf) // ${KERNEL}/kernel/bpf/syscall.c
|-->__sys_bpf()
|-->link_update()
|-->link->ops->update_prog()
|
由 “bpf link 创建过程” 可知,link->ops
为 &bpf_xdp_link_lops
,因此 link->ops->update_prog()
实际上是调用了 bpf_xdp_link_update()
函数。
link->ops->update_prog()
不涉及 bpf link 本身的更新,而是由各个 bpf link 类型自己实现的。在此,就不展开各个类型的具体实现了。
bpf link 卸载过程
卸载 XDP bpf prog 的实现过程如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
SYSCALL_DEFINE3(bpf) // ${KERNEL}/kernel/bpf/syscall.c
|-->__sys_bpf()
|-->link_detach()
|-->link->ops->detach()
|**>bpf_xdp_link_detach() // ${KERNEL}/net/core/dev.c
| |-->bpf_xdp_link_release()
| |-->dev_xdp_detach_link() // 具体的 detach 过程
|-->bpf_link_put_direct()
|-->bpf_link_free()
|-->link->ops->dealloc()
|**>bpf_xdp_link_dealloc() // ${KERNEL}/net/core/dev.c
|-->kfree(link)
|
在卸载过程中,具体的 detach 过程由各个 bpf link 类型自己实现。
获取 bpf link 的对象信息
类似于 bpf prog,bpf link 也有自己的对象信息,即通过 bpftool link
所看到的信息。
1
2
3
4
5
6
|
# bpftool link
1: tracing prog 2
prog_type tracing attach_type modify_return
target_obj_id 1 target_btf_id 113304
42: xdp prog 331
ifindex ens33(2)
|
还是以 XDP bpf prog 为例,获取 bpf link 的对象信息的过程如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
SYSCALL_DEFINE3(bpf) // ${KERNEL}/kernel/bpf/syscall.c
|-->__sys_bpf()
|-->bpf_obj_get_info_by_fd()
|-->bpf_link_get_info_by_fd() {
| info.type = link->type;
| info.id = link->id;
| if (link->prog)
| info.prog_id = link->prog->aux->id;
| link->ops->fill_link_info(link, &info);
}
|**>bpf_xdp_link_fill_link_info() // ${KERNEL}/net/core/dev.c
|-->info->xdp.ifindex = link->dev->ifindex;
|
以上代码片段展示了获取 XDP bpf link 的对象信息的过程。
- 通过 bpf link 获取基本的
type
和 id
信息。
- 如果 link 有 prog,获取 prog 的
id
信息。
- 调用
link->ops->fill_link_info()
来填充 link 具体类型对应的详细信息。
总结
bpf link 的引入是为了解决 bpf prog attachment 持久化的问题,并由此引入了 bpf link fd。
bpf link 的创建过程主要包括以下几个步骤:
- 创建 bpf link 使用的内存。
- 初始化 bpf link。
- 分配 fd, ID,和创建一个匿名 file,缓存到 bpf prime 里。
- bpf prog 的 attach 过程。
- 将 ID 转给 bpf link,并将 fd 和 file 关联起来。
bpf link 的更新过程由各个 bpf link 类型自己实现。
bpf link 的卸载过程由各个 bpf link 类型自己实现。
bpf link 的对象信息通过 bpftool link
来获取。其实,也可以通过 fdinfo 来获取:
1
2
3
4
5
6
7
8
9
10
|
# cat /proc/728267/fdinfo/10
pos: 0
flags: 02000000
mnt_id: 16
ino: 68
link_type: xdp
link_id: 43
prog_tag: 3b185187f1855c4c
prog_id: 343
ifindex: 2
|
《XDP 进阶手册》里详细讲解了 XDP attachment 的源码细节。
欢迎加入「eBPF Talk」知识星球,学习更多 XDP 知识。