初识 BPF:从 Hello World 开始的内核编程之旅

news2024/12/24 2:41:52

Part 1 概述

1. 背景

BPF 技术被列为近些年 Linux 内核领域最火热的新领域之一。它成功的给 Linux 内核赋予了少量的动态可编程性,可以在 Linux 内核运行时,实时修改内核的行为,但不需要重新编译和重启内核。据此,BPF 在 Linux 世界中:

  • 网络
  • 可观测性
  • 安全

三大领域大放异彩,学习好 BPF 技术,对于 Linux 内核和应用开发者来说,是一件非常有意义的事情。

2. 什么是 BPF?

BPF 在 Linux 内核中,被实现为一个非常精简的虚拟机,具有几乎性能无损的执行效率。我们可以用类似 C 语言的语法,编写代码,编译成可以在 BPF 虚拟机中运行的汇编代码,实现其强大的逻辑处理能力。

今天,我们将从 Hello World 开始,带您进入 BPF 的世界。

3. 开始 BPF

按照计算机程序设计语言学习的传统,我们从经典的 Hello World 程序开始我们的 eBPF 开发之旅。首先简单对比下标准 C 程序和 eBPF 程序的异同。

C 语言程序

# HelloWorld.c

#include <stdio.h>

int main()
{
 printf("HelloWorld\n");
 return 0;
}

# C 语言的编译与运行

eBPF 程序

# HelloWorld.bpf.c

#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>

int helloworld(void *ctx)
{
 bpf_printk("Hello world!\n");
 return 0;
}

# eBPF 程序的编译与运行

eBPF 的编译、加载、运行比标准 C 程序要麻烦一些。接下来会一步一步介绍全流程。

Part 2 开发环境

我们使用 vagrant + virtualbox +Ubuntu22.04 组建我们的开发环境。注意,只支持 X86 的 CPU (Windows, Linux 或 Mac)。苹果 M 芯片不支持。

保存虚拟机描述文件 Vagrantfile:

Vagrant.configure('2') do |config|
  config.vm.define 'bpf' do |bpf|
    bpf.vm.provider 'virtualbox' do |vb|
      vb.gui = false
      vb.memory = '4096'
      vb.cpus = 2
    end
    bpf.vm.synced_folder '.', '/vagrant', disabled: true
    bpf.vm.box = 'bento/ubuntu-22.04'
    bpf.vm.network 'private_network', type: 'dhcp'
    bpf.vm.provision 'shell', inline: <<-SHELL
        set -x
        set -e
        apt-get install -y linux-tools-generic linux-tools-$(uname -r) gcc-multilib clang libbpf0 libbpf-dev
    SHELL
  end
end

一些常用命令:

  • vagrant up: 启动虚拟机
  • vagrant halt: 关闭虚拟机电源
  • vagrant detroy: 销毁虚拟机
  • vagrant ssh: 登入虚拟机

Part 3 开始开发


以上文提到的 HelloWorld.bpf.c 为例子。

1. 编译 eBPF

生成 eBPF 字节码,并带有调试信息:

clang -target bpf -Wall -O2 -g -c HelloWorld.bpf.c -o HelloWorld.o

查看 eBPF 编译后的字节码:

llvm-objdump -d -r -S --print-imm-hex HelloWorld.o
root@vagrant:~# llvm-objdump -d -r -S --print-imm-hex HelloWorld.o

HelloWorld.o:   file format elf64-bpf

Disassembly of section .text:

0000000000000000 <helloworld>:
; {
       0:       b7 01 00 00 0a 00 00 00 r1 = 0xa
;  bpf_printk("Hello world!\n");
       1:       6b 1a fc ff 00 00 00 00 *(u16*)(r10 - 0x4) = r1
       2:       b7 01 00 00 72 6c 64 21 r1 = 0x21646c72
       3:       63 1a f8 ff 00 00 00 00 *(u32*)(r10 - 0x8) = r1
       4:       18 01 00 00 48 65 6c 6c 00 00 00 00 6f 20 77 6f r1 = 0x6f77206f6c6c6548 ll
       6:       7b 1a f0 ff 00 00 00 00 *(u64*)(r10 - 0x10) = r1
       7:       bf a1 00 00 00 00 00 00 r1 = r10
       8:       07 01 00 00 f0 ff ff ff r1 += -0x10
;  bpf_printk("Hello world!\n");
       9:       b7 02 00 00 0e 00 00 00 r2 = 0xe
      10:       85 00 00 00 06 00 00 00 call 0x6
;  return 0;
      11:       b7 00 00 00 00 00 00 00 r0 = 0x0
      12:       95 00 00 00 00 00 00 00 exit

2. 运行 BPF

流程

Linux 内核中支持 eBPF 的事件很多。挂载 eBPF 程序后,需要等待事件异步触发才能看到效果。

加载 eBPF 字节码

Linux 内核官方工具 bpftool 帮我们封装了对 eBPF 字节码各种操作。本文我们用它来挂载和调试 eBPF。

# 在内核生成 eBPF 文件结构

eBPF 在 Linux 内核以特殊文件形式存在,如果进程退出了则会自动销毁。为了让 eBPF 程序独立于进程持久存在于 Linux 内核中,内核提供了 bpf 文件系统,可以把 eBPF 程序 pin 在其中。Ubuntu 22.04 默认挂载了 bpf 文件系统,位于 /sys/fs/bpf,可以直接使用。

现在的 eBPF 字节码只是一段单纯的代码,要把它传入内核,还需要指定该 eBPF 字节码的类型,可以通过 bpftool feature 列出内核支持的所有 eBPF 类型:

 
...
Scanning eBPF program types...
eBPF program_type socket_filter is available
eBPF program_type kprobe is available
eBPF program_type sched_cls is available
eBPF program_type sched_act is available
eBPF program_type tracepoint is available
eBPF program_type xdp is available
eBPF program_type perf_event is available
eBPF program_type cgroup_skb is available
eBPF program_type cgroup_sock is available
eBPF program_type lwt_in is available
eBPF program_type lwt_out is available
...

HelloWorld.bpf.c 是一个 "万能" 的 eBPF 程序,因为它仅仅输出 "HelloWorld",因此,它可以指定为任何 eBPF 程序类型,这里我们选用 raw_tracepoint。

bpftool prog load HelloWorld.o /sys/fs/bpf/HelloWorld type raw_tracepoint

现在可以在 /sys/fs/bpf/ 中看到:

root@vagrant:~# ls /sys/fs/bpf/HelloWorld
/sys/fs/bpf/HelloWorld

或者:

root@vagrant:~# bpftool prog show pinned /sys/fs/bpf/HelloWorld
353: raw_tracepoint  name helloworld  tag fc3c56cde923df12  gpl
        loaded_at 2023-03-11T01:59:48+0000  uid 0
        xlated 104B  jited 71B  memlock 4096B
        btf_id 118

这说明我们的 eBPF 程序已经成功加载到内核中。

#把内核中的 eBPF 程序挂载到事件上

正常情况下,我们会把 eBPF 挂载到特定事件上,然后等待事件异步触发时,再执行 eBPF 程序。

本文我们为了方便,选择最简单的,用于调试和测试用的接口:BPF_PROG_TEST_RUN,也叫 BPF_PROG_RUN,

他们是完全等价的。这个接口可以直接同步执行 eBPF 程序,而不需要挂载到事件上再等待事件异步发生。

BPF_PROG_TEST_RUN 只支持有限的 eBPF 程序类型:

BPF_PROG_TYPE_SOCKET_FILTER
BPF_PROG_TYPE_SCHED_CLS
BPF_PROG_TYPE_SCHED_ACT
BPF_PROG_TYPE_XDP
BPF_PROG_TYPE_SK_LOOKUP
BPF_PROG_TYPE_CGROUP_SKB
BPF_PROG_TYPE_LWT_IN
BPF_PROG_TYPE_LWT_OUT
BPF_PROG_TYPE_LWT_XMIT
BPF_PROG_TYPE_LWT_SEG6LOCAL
BPF_PROG_TYPE_FLOW_DISSECTOR
BPF_PROG_TYPE_STRUCT_OPS
BPF_PROG_TYPE_RAW_TRACEPOINT
BPF_PROG_TYPE_SYSCALL

上文我们把 eBPF 字节码指定为 raw_tracepoint,正好满足该接口的要求。

利用 bpftool 使用 BPF_PROG_TEST_RUN 接口来运行它 (参数如何设置,之后会有专题分析,这里不要修改 bpftool 参数):

bpftool prog run pinned /sys/fs/bpf/HelloWorld repeat 0

查看输出结果:

root@vagrant:~# cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 1/1   #P:4
#
#                                _-----=> irqs-off
#                               / _----=> need-resched
#                              | / _---=> hardirq/softirq
#                              || / _--=> preempt-depth
#                              ||| / _-=> migrate-disable
#                              |||| /     delay
#           TASK-PID     CPU#  |||||  TIMESTAMP  FUNCTION
#              | |         |   |||||     |         |
         bpftool-39498   [001] d.... 979047.864950: bpf_trace_printk: Hello world!

OK, 我们现在成功的执行了第一个最简单的 BPF 程序。

Part 4 BPF in MatrixOne

MatrixOne 作为我司主打数据库产品,未来在 MatrixOne 中将全面使用 BPF 技术,用于增强数据库集群的性能,稳定性和安全性。

网络

MatrixOne 作为云原生数据库,运行在标准的 Kubernetes 集群中,网络是其最重要的基础设施之一。我们将利用 BPF 技术,减少 Linux 内核网络协议栈的开销,实现 MatrixOne 的网络性能优化。

可观测性

我们将在自带的可观测性组件中,利用 BPF 实时采集和分析数据库运行时的各种指标,用于自动化分析和故障诊断。同时,我们将提供一系列 BPF 工具,用于 SRE 人工分析和调优 MatrixOne。

安全性

我们将在附属的安全组件中,提供基于 BPF 得关键操作监控和禁止操作,用于实时检测和防御数据库的安全威胁。

关于 MatrixOne

MatrixOne 是一款基于云原生技术,可同时在公有云和私有云部署的多模数据库。该产品使用存算分离、读写分离、冷热分离的原创技术架构,能够在一套存储和计算系统下同时支持事务、分析、流、时序和向量等多种负载,并能够实时、按需的隔离或共享存储和计算资源。云原生数据库 MatrixOne 能够帮助用户大幅简化日益复杂的 IT 架构,提供极简、极灵活、高性价比和高性能的数据服务。

MatrixOne 企业版和 MatrixOne 云服务自发布以来,已经在互联网、金融、能源、制造、教育、医疗等多个行业得到应用。得益于其独特的架构设计,用户可以降低多达 70% 的硬件和运维成本,增加 3-5 倍的开发效率,同时更加灵活的响应市场需求变化和更加高效的抓住创新机会。在相同硬件投入时,MatrixOne 可获得数倍以上的性能提升。

MatrixOne 秉持开源开放、生态共建的理念,核心代码全部开源,全面兼容 MySQL 协议,并与合作伙伴打造了多个端到端解决方案,大幅降低用户的迁移和使用成本,也帮助用户避免了供应商锁定风险。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1709847.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java面试(多线程)

线程和进程的区别 程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至CPU&#xff0c;数据加载至内存。在指令运行过程中还需要用到磁盘&#xff0c;网络等设备。进程就是用来加载指令&#xff0c;管理内存&#xff0c;管…

鲲鹏迁移——DevKit

参考文档 鲲鹏DevKit开发套件下载-鲲鹏社区鲲鹏社区是面向鲲鹏合作伙伴、开发者的全产业社区&#xff0c;集学习、实验、认证等功能为一体&#xff0c;是鲲鹏计算产业的官方社区。https://www.hikunpeng.com/developer/devkit/download 鲲鹏社区-官网丨凝心聚力 共创行业新价…

记录一次开源 MaxKey 安装部署

官方文档&#xff1a;https://www.maxkey.top/doc/docs/intro/ 开源代码&#xff1a;https://toscode.mulanos.cn/dromara/MaxKey 发行版&#xff1a;https://toscode.mulanos.cn/dromara/MaxKey/releases 一、准备工作 yum install -y yum-utils yum-config-manager --add-r…

CSS 之 自定义属性(变量)

一、简介 ​ CSS的自定义属性&#xff0c;又称为CSS变量或级联变量&#xff0c;用于定义一个带有值的、可重复使用的CSS属性&#xff08;变量&#xff09;。其包含的值可以在其作用域内的任意属性上重复使用&#xff0c;在使用时需要借助var()函数获取自定义属性的值。当自定义…

text-embedding 嵌入模型

为什么使用embedding 计算机只能处理数字&#xff0c;但我们希望它能够理解文字、图片或其他形式的数据。这就是embedding的作用。它将这些复杂的数据转换成数字表示&#xff0c;就像给它们贴上了标签一样。这些数字表示不仅保留了原始数据的重要信息&#xff0c;还能在计算机…

短视频商城全套源码:开启电商新纪元

随着数字媒体的快速发展&#xff0c;短视频平台已经成为人们获取信息、娱乐和社交的重要渠道。在这样一个大背景下&#xff0c;短视频商城的兴起&#xff0c;无疑为电商行业带来了新的机遇和挑战。本文将探讨短视频商城全套源码的重要性&#xff0c;以及它如何助力商家和开发者…

Vulnhub - AI-WEB-1.0靶机教程

目录 站点信息收集 c段扫描 端口扫描 目录扫描 漏洞利用 使用 burp 抓包 查询数据库名 查询数据库下的表 查询表中的字段名 查询字段中的数据 --os-shell 上传一句话木马 下载地址&#xff1a;https://download.vulnhub.com/aiweb/AI-Web-1.0.7z 我们从站点信息收…

2024年区块链,物联网与信息技术国际会议(ICBITIT 2024)

2024年区块链&#xff0c;物联网与信息技术国际会议&#xff08;ICBITIT 2024&#xff09; 2024 International Conference on Blockchain, Internet of Things, and Information Technology 会议简介&#xff1a; 2024年区块链&#xff0c;物联网与信息技术国际会议&#xff…

【调试笔记-20240528-Linux-用 OpenWrt-23.05 SDK 编译 frp 软件包】

调试笔记-系列文章目录 调试笔记-20240528-Linux-用 OpenWrt-23.05 SDK 编译 frp 软件包 文章目录 调试笔记-系列文章目录调试笔记-20240528-Linux-用 OpenWrt-23.05 SDK 编译 frp 软件包 前言一、调试环境操作系统&#xff1a;Ubuntu 22.04.4 LTS编译环境调试目标 二、调试步…

java函数编程-黑马学习笔记

第一章 01合格的函数 函数就是一个规则 合格的函数就是只要你输入相同&#xff0c;无论多少次调用&#xff0c;不论什么时间调用&#xff0c;输出是相同的。 函数可以引用外部的数据&#xff0c;但是需要去保证外部的数据不可变 static关键字修饰的静态方法本质上和函数没…

TCP 与 UDP

0. tcp 与 udp 的 异同特性 TCPUDPname传输控制协议用户数据报协议面向连接&#xff1f; 需要 传输数据前建立连接传输完毕后断开连接不需要可靠的传输数据&#xff1f; 可靠 有确认机制&#xff08;三次握手&#xff09; 有确认、窗口、重传、拥塞控制的机制保证数据可靠传输…

10Django项目--用户管理系统--改

对应视频链接点击直达 10Django项目--用户管理系统--改 对应视频链接点击直达改a&#xff0c;本质b&#xff0c;修改(更新) 页面相关a&#xff0c;index页面新增操作按钮b&#xff0c;修改(更新)页面c&#xff0c;路由和函数 OVER&#xff0c;不会有人不会吧不会的加Q139400651…

项目9-网页聊天室3(主界面之用户信息)

1.前端页面 CSS: 如何让img里的图片自适应div&#xff0c;且不变形_img自适应div大小 铺满且不变形-CSDN博客 JavaScript/jQuery 如何改变一个img元素的src属性|极客教程 (geek-docs.com) 2.要求 左上角显示用户的昵称和头像. 3.后端代码 3.1 添加拦截器 3.2 注册拦截器 …

深入解析MySQL 8中的角色与用户管理

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 &#x1f38f;&#xff1a;你只管努力&#xff0c;剩下的交给时间 &#x1f3e0; &#xff1a;小破站 深入解析MySQL 8中的角色与用户管理 前言角色和用户的基础概念用户&#xff08;User&#xff09;…

收银系统源码--零售连锁店铺如何选择适合自己的收银系统?

如果你现在还认为小便利店只要简单的收款&#xff0c;只有大型的连锁便利店才需要收银软件和管理软件&#xff0c;那你就错了&#xff0c;连锁品牌的便利店是必须要用到专业的收银软件&#xff0c;但是小微型的便利店更应该要用专门的软件&#xff0c; 在各行各业逐步革新互联网…

【ai】LiveKit Agent 的example及python本地开发模式工程实例

title: ‘LiveKit Agent Playground’ playgroundLiveKit Community playground的环境变量&#xff1a;LiveKit API # LiveKit API Configuration LIVEKIT_API_KEYYOUR_API_KEY LIVEKIT_API_SECRETYOUR_API_SECRET# Public configuration NEXT_PUBLIC_LIVEKIT_URLwss://YOUR_…

计算机网络基础 - 计算机网络和因特网(1)

计算机网络基础 计算机网络和因特网什么是 Internet?具体构造的的角度服务角度网络结构 网络边缘网络核心电路交换分组交换概述排队时延和分组丢失转发表和路由选择协议按照有无网络层的连接 分组交换 VS 电路交换 接入网DSL 因特网接入电缆因特网接入光纤到户 FTTH无线接入网…

十五、Python模块 1、(入门一定看!!!)「长期更新Python简单入门到适用」

首先什么是模块&#xff1f; 小伙伴们经常看我写的教程不难发现&#xff0c;前面我们用过几次模块就是sys的那个&#xff0c;其实python不仅标准库中包含了大量的模块&#xff08;也被称之为准模块&#xff09;&#xff0c;还有大量的第三方模块&#xff0c;开发者也可以自己发…

图卷积神经网络的简史 及其与卷积神经网络的异同

图卷积神经网络&#xff08;GCN&#xff09;已经在处理图结构数据方面取得了巨大的成功。在本小节中&#xff0c;我们将深入探讨图卷积神经网络的起源、发展历程&#xff0c;并提供一个简单的Python代码实现示例&#xff0c;以帮助读者更好地理解这一概念。 图卷积神经网络的简…

Echarts图表库推荐以及使用Echarts实现饼图端头弧形效果

推荐Echarts图表库官方链接http://www.ppchart.com/#/ 下面是一段实现饼图端头弧形效果的Echarts代码 下面代码可以直接新建html文件运行看效果也可以看我下面贴的效果图 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&q…