0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

BPF为内核编程提供了一个新的参考模型

Linux阅码场 来源:Linux阅码场 作者:Linux阅码场 2022-10-19 11:27 次阅读

无论好坏,C语言已经是内核开发领域的通用语言了。Linux 内核的核心逻辑完全是用 C 语言编写的(加上一点汇编),它的驱动程序和 module 也是如此。虽然 C 语言因其强大而简单的语义而受到赞誉,但它是一种古老的语言,缺乏现代语言(如 Rust)中的许多特性。另一方面,BPF 子系统也提供了一个编程环境,工程师能够编写可以在内核空间安全运行的程序。在爱尔兰都柏林举行的 2022 年 Linux Plumbers Conference 上,Alexei Starovoitov 概述了 BPF 多年来的发展,为内核编程提供了一个新的参考模型。

BPF的使命

Starovoitov 首先描述了他对 BPF 的 "mission statement, 使命宣言":"创新、并启发大家创新"。内核中的编程历来是在两种情况下进行的:

core kernel 开发,包括主要的核心子系统,如内存管理、调度器、read-copy-update,等等。

kernel-module 开发,指的是构建那些不被编译到 main kernel image 里的内容,由 module loader 在后续加载。例如,驱动程序被写成一些内核 module,也有其他功能是这么做的,如文件系统、网络协议等等。

这是内核在很长一段时间内的状态,直到 3.15 版的内核中加入了最早版本的 extended BPF(eBPF)虚拟机。有了它之后,BPF program 可以用一个受到严格限制的 C 语言来编写,并被编译成 BPF 字节码,这将允许用户编写的代码可以经过验证确保安全,然后再在内核空间运行。

从那时起,BPF 在代码的规模、用户及贡献者社区的规模方面都稳步增长。根据 Starovoitov 的说法,BPF 邮件列表上每天都会收到 50-70 条信息,每月大约收到 2000 封邮件。平均每月里活跃贡献的 BPF 贡献者的数量也在同步增长,截至 2022 年 9 月,已达到约 140 人。目前来说,对 BPF 子系统的大部分贡献都不是来自 Meta BPF 小组了。

BPF编程环境

虽然大多数 BPF 程序是用 C 语言编写的,并用 LLVM Clang 编译器编译,但 BPF program 只是二进制 BPF 字节码对象文件,并未规定要用某种特定的语言来写。比如说,BPF 程序可以使用 Aya 来采用 Rust 编写,甚至可以直接用 BPF 汇编语言编写。也就是说,C是 BPF 程序的典型(canonical)编程语言;Starovoitov 的演讲继续概述了 BPF program 开发中 C 编程环境是如何演进的。

这个新的编程环境混合使用了 C 语言扩展以及运行时环境的组合实现的,这个运行时环境包含了 Clang、用户空间的 BPF 加载器库(libbpf)和内核中的 BPF 子系统。要想创建一个 BPF 程序,用户只要用 C 语言写一个程序,由 Clang 的 backend 实现来转换成 BPF 指令。在运行程序时,libbpf 将 BPF 程序加载到内存中,对程序进行重定位以使其可以跨平台以及不同的内核版本从而具备良好的可移植性,然后调用 kernel 来加载程序。最后在内核中,verifier 会采用静态方式验证该程序是否可以安全运行,然后启用之。

然而,BPF 的编程环境并不是一上来就这么丰富的。在 BPF 的早期,程序被要求使用 Starovoitov 所说的 "restricted C"。BPF 程序中的所有函数都必须完全是 inline 的,loop 循环、静态变量和全局变量以及内存分配都是不允许的。也没有类型信息(type information),所以 BPF 程序只能接收单一的、固定的 input context,用于 tracing 以及 network-filtering 相关功能。

尽管在这样一个高度限制性的环境中编写 BPF 程序也是很有用的,但很明显, BPF 所支持的使用场景还可以得到很大的扩展。其中一个扩展就是允许在 BPF 程序中使用静态函数。这样做需要使用 libbpf 在程序加载时对内核 BPF 程序进行重定位。经过多年的设计和尝试,最终也增加了对有限循环的支持,此外也支持了 iterator。

Extending the programming environment past full C

虽然这些使得 BPF 更接近于完整的 C 语言了,但最终可以看到,BPF 程序需要的一些功能甚至在完整的 C 语言标准中都没有。于是 BPF 社区开始扩展 BPF 编程环境,从而包括一些传统 C 语言没有的新特性。其中一个扩展功能就是 "一次编译-到处运行"(CO-RE, Compile Once - Run Everywhere)。

CO-RE 使 BPF 程序可以在不同的内核版本和平台上都可以运行。在 BPF 程序中,访问内核数据结构是很常见的行为。然而,内核没有为 struct layer 确保 ABI 不变,因此,如果内核结构在未来的版本或不同的 config 下发生了变化,在固定偏移的地方对内核结构进行读取的 BPF 程序可能就会读到错误的值。CO-RE 通过利用运行中的内核中的 BPF 类型格式(BTF)数据来解决这个问题。在加载一个程序时,libbpf 对所有的 struct 的访问都会进行重定位,以便根据当前运行的内核的 BTF 信息让被访问的字段的偏移量匹配上。

Starovoitov 还描述了 BPF 编程环境的其他一些有趣的新增功能。其中一个是 kptrs,它允许将内核内存的指针存储在 BPF map 中。另一个功能是允许程序在加载时访问内核 config 参数。内核 module 只能使用编译时设置的 config 值,但 BPF 程序在加载时可以根据当前内核的配置来决定自己的行为。还有一个特点是 "type tags",可以让程序能对变量进行 annotation,从而描述它们的使用方式。例如,kptrs 可以用 __kptr 和 __kptr_ref type tags 来进行标注,从而表明它们分别是 unreferenced 或者 referenced kptr。当然指针也可以用 __user 或 __percpu 标准,来告诉编译器和 verifier 这个指针分别指向用户内存或 per-CPU 内存。

Plans for the future

目前正在设计和实现更多的扩展,包括 lock-correctness 正确性验证,以及支持 BPF 程序包含 assertion。lock 的验证乍一看似乎是一个很难解决的问题,而 Dave Marchevsky 和 Kumar Kartikeya Dwivedi 都已经发出了 RFC patch set 来实现用于 lock 验证的新 map type。Marchevsky 的 patch set 提出了一个新的红黑树 map type,而 Dwivedi 的 patch set 提出了一个 list map type。这两个 patch set 都实现了共同的效果,允许 BPF 程序执行由 verifier 检查和验证过的 locking 机制。

assertion 验证仍处于规划阶段,实现起来可能会很复杂。assertion 将作为给编译器和 verifier 的信号,assertion 被用来指示程序中的一些不变的因素,这些不变因素的失败将导致程序中止。Starovoitov 声称,弄清如何让程序中止,这会是一个 "有趣" 的问题,因为它需要安全地对堆栈进行 unwind,调用 kptr destructor,以及其他收尾工作。

Starovoitov 在演讲的最后分享了他对 BPF 未来的观点:会取代内核模块成为扩展内核的有效方式。早期版本的 BPF 程序看起来更像是带有固定的 BPF helper function 和固定的 map type 的用户空间程序,而如今新的 BPF 已经可以让用户在更多个性化使用场景下对内核进行扩展。事实上,这样的使用场景已经在 upstream 社区被提出来了。在 Starovoitov 之后在 LPC 发言的 Benjamin Tissoires,一直在开发一个 patch set,希望用 BPF 程序来 fix 人类输入设备(HID)的 quirk。到目前为止,还没有一个内核 module 被 BPF 程序完全取代掉,不过,很期待看到内核的其他一些功能可以在 BPF 程序中实现。

一位听众要求了解 Starovoitov 所提到的 lock-correctness 验证的更多细节。Starovoitov 说,这个工作还在进行当中,但他乐观地认为可以找到一种方法来进行 static lock checking,从而验证数据保护是正确的,并保证不会发生死锁。Dave Miller 回应说,如果锁可以由 verifier 进行静态检查,那么可能可以研究一下 locking 逻辑是否可以由 verifier 自动生成。Starovoitov 回答说,这就是他们希望实现的目标,目前的设计中将 lock 和受保护的数据在同一次 allocation 中放在一起。对于不能跟 lock 放在一起的数据,可以用 BTF type tag 来指定它需要明确进行锁保护。

审核编辑 :李倩

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7598

    浏览量

    136207
  • 编程
    +关注

    关注

    88

    文章

    3592

    浏览量

    93598
  • 驱动程序
    +关注

    关注

    19

    文章

    826

    浏览量

    47959
  • BPF
    BPF
    +关注

    关注

    0

    文章

    24

    浏览量

    3977

原文标题:LWN:让BPF成为一个更安全的内核编程环境!

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    THS3001构建简单的SPICE模型

    电子发烧友网站提供THS3001构建简单的SPICE模型.pdf》资料免费下载
    发表于 10-29 10:11 0次下载
    <b class='flag-5'>为</b>THS3001构建<b class='flag-5'>一</b><b class='flag-5'>个</b>简单的SPICE<b class='flag-5'>模型</b>

    接口芯片的编程模型方法是什么

    、以太网控制器,也可以是特定于应用的,如用于特定传感器或执行器的接口。 2. 编程模型的重要性 编程模型定义软件如何与硬件接口交互。
    的头像 发表于 09-30 11:30 169次阅读

    NVIDIA助力提供多样、灵活的模型选择

    在本案例中,Dify 以模型中立以及开源生态的优势,广大 AI 创新者提供丰富的模型选择。其集成的 NVIDIAAPI Catalog、NVIDIA NIM和Triton 推理服务器
    的头像 发表于 09-09 09:19 434次阅读

    为了学习内核开发,大佬手搓轻量级操作系统YiYiYa OS

    一小个模块都提供基本的功能。按各自的职责划分,分别对应与传统内核层则为核心领域业务。每一小个模块都提供基本的功能。按各自的职责划分,分别对应
    发表于 08-30 14:57

    为了学习内核开发,大佬手搓轻量级操作系统YiYiYa OS

    对应与传统内核层则为核心领域业务。每一小个模块都提供基本的功能。按各自的职责划分,分别对应与传统操作系统的内存管理、进程通信、文件系统、进程通信、等等。在演进操作系统时候,可以修改这里,对应源码目录
    发表于 08-27 10:08

    Stack Overflow与OpenAI签订协议模型提供数据

    OpenAI与知名的软件开发者问答论坛Stack Overflow达成了重要合作,旨在提升生成式人工智能模型编程领域的性能。根据双方周宣布的合作协议,OpenAI将利用Stack Overflow的丰富数据资源,不断优化其人
    的头像 发表于 05-09 09:25 358次阅读

    【大语言模型:原理与工程实践】大语言模型的应用

    输出的关键词或短语。对于任何输入,大语言模型都会根据提示词提供相应的输出。例如,“天空是”就是提示词,引导模型输出关于天空的描述。提示词
    发表于 05-07 17:21

    【大语言模型:原理与工程实践】揭开大语言模型的面纱

    维基百科、网页内容和书籍等,不仅掌握语言的语法、语义和上下文信息,还能生成结构连贯、语义合理的句子和段落。大语言模型显著特点是其庞大的参数量,已达数亿甚至数十亿级别。这种规模赋
    发表于 05-04 23:55

    【大语言模型:原理与工程实践】探索《大语言模型原理与工程实践》

    的未来发展方向进行了展望,包括跨领域、跨模态和自动提示生成能力方向,读者提供对未来技术发展的深刻见解。《大语言模型原理与工程实践》是
    发表于 04-30 15:35

    谷歌发布用于辅助编程的代码大模型CodeGemma

    谷歌发布用于辅助编程的代码大模型 CodeGemma。CodeGemma 基于谷歌今年 2 月发布的轻量级开源大模型 Gemma,针对 Gemma 的两
    的头像 发表于 04-17 16:07 634次阅读
    谷歌发布用于辅助<b class='flag-5'>编程</b>的代码大<b class='flag-5'>模型</b>CodeGemma

    使用iLD API对TC357进行编程,如何将其两ADC内核配置同时连续地采样?

    使用 iLD API 对 TC357 进行编程,如何将其两 ADC 内核配置同时连续地对以下两通道进行采样: AN2 (EVADC_
    发表于 01-18 07:12

    AI引擎内核与计算图编程指南

    电子发烧友网站提供《AI引擎内核与计算图编程指南.pdf》资料免费下载
    发表于 01-03 10:50 0次下载
    AI引擎<b class='flag-5'>内核</b>与计算图<b class='flag-5'>编程</b>指南

    LabVIEW进行癌症预测模型研究

    ,然后将得到的特征向量输入到SVM中进行分类。 LabVIEW是种视觉编程语言,与传统的文本编程语言不同,更适合于进行复杂数据分析和预测模型的开发。 LabVIEW使用数据流
    发表于 12-13 19:04

    如何从简单的数学表达式创建Saber模型

    如何从简单的数学表达式创建Saber模型,将你的输出描述输入的函数?例如 out=a*
    的头像 发表于 12-05 13:42 687次阅读
    如何从<b class='flag-5'>一</b><b class='flag-5'>个</b>简单的数学表达式创建<b class='flag-5'>一</b><b class='flag-5'>个</b>Saber<b class='flag-5'>模型</b>?

    NVIDIA 部分大型亚马逊 Titan 基础模型提供训练支持

    本文将介绍亚马逊如何使用 NVIDIA NeMo 框架、GPU 以及亚马逊云科技的 EFA 来训练其 最大的新代大语言模型(LLM)。 大语言模型切都很庞大——巨型
    的头像 发表于 11-29 21:15 513次阅读
    NVIDIA <b class='flag-5'>为</b>部分大型亚马逊 Titan 基础<b class='flag-5'>模型</b><b class='flag-5'>提供</b>训练支持