LWN:用BPF来修改kernel里的operation structure!

关注了就能看到更多这么棒的文章哦~

Kernel operations structures in BPF

By Jonathan Corbet
February 7, 2020

原文来自:https://lwn.net/Articles/811631/

在5.6 kernel将要包含的功能中,有一个会引起许多人的兴趣:支持加载BPF program来配置TCP拥塞控制算法(TCP congestion-control algorithms)。用网络部分的开发者Toke Høiland-Jørgensen的说法来说:“这是把kernel变成一个基于BPF runtime的微内核的又一进展”。拥塞控制是最新交给BPF的一个新任务,这已经远远超出了当初设计BPF的时候的目标。不过,如果细细看进去的话,肯定会感到更加惊讶,因为这个功能的实现方式打破了许多领域的惯例!

这个功能的使用场景再明显不过了。目前已经有许多拥塞控制算法在用了,每种都有各自特别适用的特定网络条件。因此产生了动态选择拥塞控制算法而不用重新编译kernel以及重启系统。网络开发者也可以更加轻松地来实验拥塞控制算法。有人可能会提出异议,认为拥塞控制本质上与其他那些flow disp或者IR protocol decoding这些任务没有什么区别,它们都可以用BPF来实现了,拥塞控制应该也可以。不过,事实上,拥塞控制的调整要复杂的多。

仔细看看Martin KaFai Lau的patch set就知道,合入5.6的这个功能不仅仅是在TCP拥塞控制算法这里加了个BPF hook而已,而是一个更加通用的方案。具体来说,新加的这个功能可以用来在kernel里让BPF program替换任意的“operation structure”(就是一个全是各种函数指针的结构体)。目前来说,还只能替换tcp_congestion_ops这个结构体里的内容,从而改变拥塞控制算法。不过按我们的经验,不就之后就会有许多其他用法被人们创造出来。

The user-space API

从user-space角度来说,如果要用这个功能新加载一个operation structure需要若干步骤。首先就是利用bpf()系统调用,把每个函数都加载为一个独立的BPF program。新增的BPF_PROG_TYPE_STRUCT_OPS类型就是为了这一步定义的。给每个BPF program传入的参数中,user space都需要提供BPF type format (BTF) ID,对应着要替换的structure。BTF也是最近加入kernel的,用来描述和区分当前运行的kernel中的具体的函数与数据结构,目前主要用在对tracing function的类型检查上。

user space还需要提供一个偏移量来指明此BPF program是用来替换哪个函数的。举例来说,在struct tcp_congestion_ops里面,ssthresh()函数指针是第六个成员,因此传入的偏移量参数是5(因为从0开始计数)。不过这个API如何确保不受structure layout randomization功能的影响,目前还不是很清楚。

等到structure中每个成员对应的program加载好了,kernel就会针对每个program都返回一个对应的文件描述符。接下来,user space就可以生成类似这样的一个结构:

    struct bpf_tcp_congestion_ops {
	refcount_t refcnt;
	enum bpf_struct_ops_state state;
	struct tcp_congestion_ops data;
    };

这里的data就是要替换的结构的相同类型,这里就是struct tcp_congestion_ops。其中并不是放置了许多函数指针,而是放置那些program加载进去之后取得的相应文件描述符。结构中那些不是函数指针的成员就不用设置了,不过kernel还是会用下面的方式来替换一下。

最后一步,把这个structure加载到kernel里。大家可以想到许多方式来完成这个任务,实际上的实现方式,大多数人可能想不到。user space需要创建一个特殊的基于BPF_MAP_TYPE_STRUCT_OPS类型的BPF map。跟这个map关联在一起的是kernel中一个特殊结构对应的BTF type ID。真正替换这个结构的动作是通过把上面填好的bpf_tcp_congestion_ops放到BPF map里的第一个元素(元素0)来实现的。也可以对这个map进行query操作(查看rfcnt和state等信息)或者干脆把第一个元素删掉从而移除这个structure。

BPF map近一两年拥有了越来越多的功能。尽管如此,这次似乎也是第一次看到BPF map被这样用起来。这样的接口是否是最合适优雅的实现方式,是有争议的。不过大多数user-space开发者看不到这个接口,因为同其他BPF API一样,都会被libbpf库来封装起来。

The kernel side

要替换一个operation structure肯定需要kernel里面的一些代码来支持。user space是不能任意地替换structure内容的。为了能替换一个特定类型的structure,kernel代码需要创建下面这样的一个结构:

    #define BPF_STRUCT_OPS_MAX_NR_MEMBERS 64
    struct bpf_struct_ops {
	const struct bpf_verifier_ops *verifier_ops;
	int (*init)(struct btf *btf);
	int (*check_member)(const struct btf_type *t,
			    const struct btf_member *member);
	int (*init_member)(const struct btf_type *t,
			   const struct btf_member *member,
			   void *kdata, const void *udata);
	int (*reg)(void *kdata);
	void (*unreg)(void *kdata);
	const struct btf_type *type;
	const struct btf_type *value_type;
	const char *name;
	struct btf_func_model func_models[BPF_STRUCT_OPS_MAX_NR_MEMBERS];
	u32 type_id;
	u32 value_id;
    };

这里还有许多细节,无法在本文中介绍清楚,此结构中的一些成员是自动由宏定义来填充的。verifier_ops结构则包含了一些函数,用来验证每个替换进来的函数都是安全可靠的。patch set还对这个structure新增了一个成员:struct_access(),这是用来管控指定此结构中哪些操作可以用BPF函数来替换。

init()函数会在最开始先调用一次,来完成一些全局性的配置工作。check_member()则用来判断目标结构中的某个特定成员是否被允许用BPF来实现,而init_member()则会在这个结构中检查任何一个成员的具体值。特别指出,init_member()可以验证那些不是函数指针的成员(比如flag成员等)。reg()函数会在完成那些检查工作之后把这个替换structure注册进来,具体在拥塞控制这个场景,它会把tcp_contestion_ops结构(内容已经被换成了那些BPF program)安装到网络协议栈里面会调用到它们的地方。unreg()则反之。

这种类型的结构在创建时都会有一类的名字:structure的类型会被替换为bpf_开头。所以用来替换tcp_congestion_ops结构的就是bpf_tcp_congestion_ops。这个结构就是在user space在加载新的operation structure时要利用BTF ID来引用的structure了。最后,会在kernel/bpf/bpf_struct_ops_types.h里面增加如下一行:

    BPF_STRUCT_OPS_TYPE(tcp_congestion_ops)

最后是故意没有分号的。利用这些魔术一般的宏定义功能,在bpf_struct_ops.c里面include这个文件4次之后,一切就都准备好了,不需要创建一个注册这个structure type的特殊函数。

In closing

大家如果对tcp_congestion_ops替换功能在kernel里的实现细节感到好奇,可以参看net/ipv4/bpf_tcp_ca.c。代码库里也已经实际实现了两种算法(TCTCP和CUBIC)。

在kernel里面能任意替换operation structure的话,会有许多潜在的用法。kernel代码里面有非常多的地方都是通过这些operation structure来调用到的。举例来说,如果我们能替换security_hook_heads structure的一部分,就可以任意修改安全策略了,这就类似KRSI这个功能。如果能替换file_operations structure,就可以重新实现kernel的I/O subsystem。还有许许多多的例子可说。

目前还没有人提出来要做这些改动,不过肯定有人会对此感兴趣的。有一天,也许任何的kernel功能都可以被user space提供的BPF program来替代。这样一来,用户对自己在运行的系统就会拥有更大的自由度,不过我们一直所说的"Linux kernel"则会变得多样化,user space加载的不同代码会让它大变样。这个结果应该会非常有趣啊!

全文完

LWN文章遵循CC BY-SA 4.0许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注LWN深度文章以及开源社区的各种新近言论~

BPF and related observability tools give software professionals unprecedented visibility into software, helping them analyze operating system and application performance, troubleshoot code, and strengthen security. BPF Performance Tools: Linux System and Application Observability is the industry’s most comprehensive guide to using these tools for observability. Brendan Gregg, author of the industry’s definitive guide to system performance, introduces powerful new methods and tools for doing analysis that leads to more robust, reliable, and safer code. This authoritative guide: Explores a wide spectrum of software and hardware targets Thoroughly covers open source BPF tools from the Linux Foundation iovisor project’s bcc and bpftrace repositories Summarizes performance engineering and kernel internals you need to understand Provides and discusses 150+ bpftrace tools, including 80 written specifically for this book: tools you can run as-is, without programming — or customize and develop further, using diverse interfaces and the bpftrace front-end You’ll learn how to use BPF (eBPF) tracing tools to analyze CPUs, memory, disks, file systems, networking, languages, applications, containers, hypervisors, security, and the Linux kernel. You’ll move from basic to advanced tools and techniques, producing new metrics, stack traces, custom latency histograms, and more. It’s like having a superpower: with Gregg’s guidance and tools, you can analyze virtually everything that impacts system performance, so you can improve virtually any Linux operating system or application.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值