[转帖]【译文】使用BPF控制内核的ops结构体

译文,使用,bpf,控制,内核,ops,结构 · 浏览次数 : 0

小编点评

## 5.6内核 TCP拥塞控制算法的新功能 5.6内核版本引入了新的 TCP拥塞控制算法,可以作为用户空间的 BPF程序进行加载和执行。 **主要特点:** * 用户空间可以动态加载新的拥塞控制算法,无需重新构建内核或重启系统。 * 算法使用 BPF 类型定义结构来描述函数和数据,方便用户空间开发。 * 算法可以替换内核中的任何 ops 结构,包括拥塞控制的 `tcp_congestion_ops` 结构。 **主要应用场景:** * 动态调整拥塞控制算法,根据网络环境进行切换。 * 支持多种拥塞控制算法,方便开发人员选择最适合的算法。 **主要优点:** * 可动态调整拥塞控制性能。 * 支持多种拥塞控制算法。 * 简化开发流程,方便用户空间开发。 **主要缺点:** * 需要内核态支持。 * 算法可能对系统性能造成一定的影响。

正文

https://zhuanlan.zhihu.com/p/105814639

 

Linux内核5.6版本的众多令人惊喜的功能之一是:TCP拥塞控制算法(congestion control algorithm)可作为用户空间的BPF(Berkeley Packet Filter)程序进行加载和执行。 网络开发者Toke Høiland-Jørgensen将这项功能描述为“内核正向成为支持BPF运行时的微内核迈进(march towards becoming BPF runtime-powered microkernel)”的延续性动作。 从外表上看,这是赋予给BPF的一项重要的新功能,使得拥塞控制将远远超过现有能力。 但当我们深入研究后发现,其令人惊喜之处远不止这些,因为该功能的实现在多个方面都取得了新的进展。

该功能的使用场景和用例似乎都比较明确,因为有大量不同的拥塞控制算法已在使用中,且每种算法都适合于不同的网络环境。 利用该功能,我们有充足方法来分发更新或改进后的控制算法,因为使用者能够在无需重新构建内核甚至无需重启的情况下使用新算法,使得网络功能开发者可从运行中的拥塞控制代码中获得好处。 有人可能会质疑,拥塞控制功能在概念上与BPF现有的其它功能(例如flow dissectionInfrared协议解码)没有本质的不同,但需要指出的是,拥塞控制确实涉及到相当高的复杂性。

如果看一下Martin KaFai Lau发布的patch集合,你就会发现5.6版本内核将要合并的代码不仅仅是一项能够hook住TCP拥塞控制的机制,其真实威力远不止于此。 具体地说,这种新架构可用于允许BPF程序替换内核中的任何“ops结构(struct xxx_ops)”——一个由函数指针组成的结构。 目前,虽然它只能替换用于拥塞控制的struct tcp_congestion_ops结构,但大量的经验表明,在内核其他地方的应用将很快涌现。

用户空间API

在用户空间中,加载新的ops结构需要如下几个步骤。首先,使用bpf()系统调用以单独的BPF程序对每个函数的实现进行加载,这些BPF程序已经可以使用新的BPF_PROG_TYPE_STRUCT_OPS类型定义ops。 用户空间在每个程序提供的属性中,必须提供与要替换的结构相对应的BPF类型格式(BPF Type Format,BTF)的ID(同时用于指定稍后要实现的实际功能)。 BTF是一项较新的特性,它描述了正在运行的内核中的函数和数据结构,目前用于追踪函数的类型检查

用户空间还必须指定一个整数偏移量,以标识此程序将要替换的函数。 例如,struct tcp_congestion_ops的函数指针字段ssthresh()在结构中位于第六个字段,因此将5作为偏移量进行传递(偏移量从0开始)。 目前还不明确该API如何与结构布局随机化(structure layout randomization)进行交互。

在加载每个结构字段对应的程序时,内核将返回与每个结构字段相对应的文件描述符。为了使用此描述符,用户空间还必须填充如下的结构:

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

上面的代码中,data字段的类型是将要替换的结构——在拥塞控制中也就是struct tcp_congestion_ops,但是,此结构应包含已加载用于实现对应拥塞控制功能的程序的文件描述符,而非函数指针。 尽管内核可以按如下所述覆盖内容,但也应根据需要设置该结构中的非函数字段。

最后一步,是将该结构加载到内核中,有多种方式来达到该目的,因此实际的实现几乎可以肯定是另外的方式。 用户空间必须使用新添加的BPF_MAP_TYPE_STRUCT_OPS类型创建一个特殊的BPF map,与该map相关联的是内核中特殊结构的BTF类型ID(如下所述),这就是将map与要替换的结构连接在一起的方式。 实际的结构替换是通过将上面的bpf_tcp_congestion_ops结构存储到零填充的map中来完成的,此外还支持的操作包括:查询map(以获取引用计数和状态字段)和通过删除元素0来删除结构。

近年来,BPF maps相关的功能和特性不断的出现,即便如此,这次添加的新功能似乎是map操作首次在内核产生类似副作用的方法。 也许本功能不是最优雅的接口,但大多数用户空间的开发者将永远看不到它背后的大部分细节,因为它就像其他大多数BPF的API一样,隐藏在libbpf库中的一系列宏和对象的背后。

内核空间

由于用户空间无权限任意替换结构,所以替换ops结构需要内核的支持,为了支持这样的替换,内核态必须新添加如下结构:

#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结构中有多个函数,可用于验证各个替换功能是否可安全执行。 在即将合并的补丁集中,该结构中添加了一个新字段:struct_access(),其用于控制BPF函数可以更改ops结构本身的哪些部分(如果有的话)。

内核在获取到用户空间的请求后,首先调用init()函数,来进行一切所必需的全局设置。 check_member()函数决定是否允许目标结构的特定成员在BPF中实现,而init_member()则用于验证该结构中所有字段的确切值,特别地,init_member()可以验证非函数字段(例如flag字段)。 在检查通过后,则通过reg()函数进行实际地注册替换结构,具体地,在拥塞控制的场景下,该函数将tcp_congestion_ops结构(和用于函数指针的BPF相关的trampoline)安装在网络栈中将要使用的位置。 相反地,unreg()则用于撤消操作。

这种类型的结构应使用特定名称创建,即添加bpf_前缀。 因此,用于替换tcp_congestion_ops结构的ops结构的名字为bpf_tcp_congestion_ops, 这是加载新的ops结构时用户空间必须(通过BTF的ID)引用的“特殊结构”。 最后,在kernel/bpf/bpf_struct_ops_types.h中添加如下的一行代码:

BPF_STRUCT_OPS_TYPE(tcp_congestion_ops)

借助宏操作,以及将此文件四次include到bpf_struct_ops.c中,便可处理好所有设置,而无需特殊的函数注册该结构类型。

总结

tcp_congestion_ops替换机制中内核态的实现可以在net/ipv4/bpf_tcp_ca.c文件中找到,源码树中已有两种不同控制算法的实现(DCTCPCUBIC)。

可替换内核中任意ops结构是一项潜在的强大功能,因为内核中很大一部分代码是通过这种类型的结构调用的。 比如说,如果可以替换全部或部分security_hook_heads结构,则可以以任意方式修改安全策略,例如,实现类似于KRSI的功能。 还有,替换file_operations结构几乎可以重写内核I/O子系统的任何部分。

目前还没有任何人提出类似的方法,但是这样的功能肯定会吸引感兴趣的开发者。 将来会有某个时刻,几乎任何内核功能都可以被用户空间的BPF代码hook或替换, 那时用户将拥有改变系统运行方式的强大能力,但是我们认为“Linux内核”将变得更加充满不确定性,这也取决于从用户空间加载了哪些代码。 结果可能会很有趣。

(译者注:本文原地址为 )

与[转帖]【译文】使用BPF控制内核的ops结构体相似的内容:

[转帖]【译文】使用BPF控制内核的ops结构体

https://zhuanlan.zhihu.com/p/105814639 Linux内核5.6版本的众多令人惊喜的功能之一是:TCP拥塞控制算法(congestion control algorithm)可作为用户空间的BPF(Berkeley Packet Filter)程序进行加载和执行。

[转帖][译] 使用 bcc/BPF 分析 Go 程序

https://toutiao.io/posts/089ydx/preview BCC 是基于 BPF 的 Linux IO 分析、监控、网络工具集合。BPF Compiler Collection (BCC) 是创建高效内核追踪和处理程序的工具包,包含几个有用的工具和用例。BCC 扩展了 BPF

[转帖][译] 星巴克不使用两阶段提交(2004)

http://arthurchiao.art/blog/starbucks-do-not-use-two-phase-commit-zh/ 译者序 本文翻译自 2004 年的一篇文章: Starbucks Does Not Use Two-Phase Commit. 由于译者水平有限,本文不免存在遗

[转帖][译]tcpdump 示例教程

https://colobu.com/2019/07/16/a-tcpdump-tutorial-with-examples/ 目录 [−] 基于IP查找流量 根据来源和目标进行筛选 根据网段进行查找 使用十六进制输出 显示特定端口的流量 显示特定协议的流量 只显示 ipv6 的流量 查看一个端口段

[转帖]使用prometheus来避免Kubernetes CPU Limits造成的事故

https://www.cnblogs.com/charlieroro/p/17074808.html 译自:Using Prometheus to Avoid Disasters with Kubernetes CPU Limits 本文将介绍Kubernetes的resource limits是

[转帖]NGINX官方文档[译]:HTTP负载均衡

负载均衡是一种优化资源利用率、提升最大吞吐量、减少延迟、提高系统容错率的常用技术。 要使用Nginx对一组服务器的HTTP流量进行负载均衡,首先需要使用upstream定义一组后端服务器(配置于http字段中),然后使用server对upstream组中的服务进行配置(同样配置于http字段中,注意

[转帖]JAVA 应用提速之 Large pages「译」

https://zhuanlan.zhihu.com/p/533305428 一、前言 我最近花了很多时间在 JVM 的内存预留代码上。它开始是因为我们得到了外部贡献,以支持在 Linux 上使用多个大小的 large page。为了以一种好的方式做到这一点,必须首先重构一些其他的东西。在沿着 内存

[转帖]JAVA 应用提速之 Large pages「译」

原文链接:https://mp.weixin.qq.com/s/HxT-DXNWkPCyDB6qAgKmXA 一、前言 我最近花了很多时间在 JVM 的内存预留代码上。它开始是因为我们得到了外部贡献,以支持在 Linux 上使用多个大小的 large page。为了以一种好的方式做到这一点,必须首先

[转帖]API架构风格对比:SOAP vs REST vs GraphQL vs RPC

https://www.cnblogs.com/charlieroro/p/14570214.html 最近一段时间关于GraphQL的讨论很多,一些项目中也相继用到了这种风格,但使用是否合理,是否存在杀鸡用牛刀这样的问题,还有待商榷。 译自:Comparing API Architectural

[转帖]API架构风格对比:SOAP vs REST vs GraphQL vs RPC

https://www.cnblogs.com/charlieroro/p/14570214.html 最近一段时间关于GraphQL的讨论很多,一些项目中也相继用到了这种风格,但使用是否合理,是否存在杀鸡用牛刀这样的问题,还有待商榷。 译自:Comparing API Architectural