当前位置: 首页 > backend >正文

ebpf简介

简介

概述: 允许用户在内核空间动态加载并执行自定义程序,从而实现对系统行为的深度监控与控制。其核心在于高性能、低侵入性和安全性。

发展:

  • cbpf:最初用于网络数据包过滤,通过在虚拟机在内核执行过滤逻辑,性能远超过用户态方案
  • ebpf:引入linux内核3.15,突破原有限制,支持更多事件类型(如系统调用、跟踪点)、更大指令集和复杂的数据结构

核心特性:

  • 动态性:无需重启系统或修改内核代码,可实时附加/移除探测点
  • 灵活性:支持几乎所有内核函数(部分保留函数如kprobe本身不可探测)
  • 低开销:ebpf程序在内核JIT编译为本地指令,执行效率高;回调函数运行时关闭抢占,避免上下文切换

核心运行机制:

  • 状态机模型:ebpf程序以内核态虚拟机运行,通过事件触发(如网络包到达、系统调用执行)激活,执行后返回结果或更新状态
  • 钩子机制:程序可挂载到内核关键位置(如kprobetracepointXDP),实现无侵入式监控,例如,tracepoint:syscalls:sys_enter_execve可捕获所有execve系统调用
  • 验证器:加载前检查程序安全性,防止无限循环、非法内存访问等,确保内核稳定性

开发步骤:

  1. 编写程序:使用c编写逻辑,通过BPF_HASH等宏定义映射,挂钩事件处理函数。例如,跟踪TCP连接与断开
  2. 编译字节码:借助llvm/clang将c代码编译成ebpf字节码
  3. 加载与验证:通过bpf()系统调用加载到内核,验证器确保代码安全

应用场景:

  • 性能监控与调优:
    • 函数调用跟踪:通过kprobe捕获内核函数执行,分析cpu热点
    • IO延迟分析:追踪块设备或网络IO延迟,定位性能瓶颈
  • 网络优化与安全:
    • DDos防护:在XDP层实时过滤恶意流量,降低内核处理开销
    • 容器网络隔离:Cilium利用ebpf实现容器间网络策略,替代iptables
  • 安全审计与防护:
    • 系统调用监控:记录敏感操作(如文件访问),检测异常行为
    • 内存保护:拦截非法内存访问,防止漏洞利用

概念

Hook

预定义钩子: ebpf程序是事件驱动的,当内核或应用程序通过某个钩子点时运行。预定义钩子包括系统调用、函数进入/退出、内核跟踪点、网络事件等

[kprobe](# kprobe)/uprobe: 如果不存在特定需求的预定义钩子,则可以创建内核探测器(kprobe)或用户探测器(uprobe),以将ebpf程序附加到内核或用户应用程序中的几乎任何位置

如何编写

  • 一般不直接编写,而是通过cilium、bcc、bpftrace、libbpf等项目间接使用。

  • 如果要直接编写,一般通过llvm将c代码编译成ebpf字节码

加载器&验证架构

概述: 当确定了所需的钩子时,可以使用bpf系统调用将ebpf程序加载到linux内核中。这通常是使用可用的ebpf库完成的

大致流程图:

在这里插入图片描述

当程序被加载到linux kernel中,会经过两个verifier验证和JIT编译步骤,然后被附加到请求的钩子上

验证

概述: 确保ebpf程序可以安全运行,验证以下条件:(这里是简单描述, 实际上挺复杂的)

  • 加载ebpf程序的进程拥有所需的权限,除非启用了非特权的ebpf,否则只有特权进程才能加载ebpf程序
  • 该程序不会崩溃或损害系统
  • 程序始终运行完成,不会死循环

JIT编译

概述: Just-in-Time编译步骤将程序的通用字节码转换为特定于机器的指令集,以优化程序的执行速度。这使得ebpf程序的运行效率与本地编译的内核代码或作为内核模块加载的代码一样高效

Maps

概述: ebpf程序的一个重要能力是共享收集的信息和存储状态,ebpf程序可以利用ebpf maps的概念在各种数据结构中存储和检索数据。ebpf maps可以从ebpf程序访问,也可以通过系统调用从用户空间中的应用程序访问。

支持的map类型:

  • 哈希表、数组
  • LRU
  • Ring Buffer
  • 堆栈跟踪
  • LPM(最长前缀匹配)

Helper Calls

概述: ebpf程序无法调用任意内核函数,允许这样做只会将ebpf程序绑定到特定的内核版本,并使程序的兼容性复杂化。相反,ebpf程序可以将函数调用转换为辅助函数,这是内核提供的众所周知且稳定的API。

可用的Helper Calls示例:

  • bpf_get_prandom_u32():生成一个32位无符号伪随机数

  • bpf_ktime_get_ns():返回系统启动以来的纳秒级单调时间(不受系统时间调整影响),常用于性能分析(如系统调用耗时)、事件时间戳记录

  • ebpf map access:

    • bpf_map_lookup_elem():通过键查找Map中的值
    • bpf_map_update_elem():更新或插入Map中的键值对
    • bpf_map_delete_elem():删除Map中的键值对
    • bpf_for_each_map_elem():遍历Map中的所有元素
  • get process/cgroup context:

    • bpf_get_current_pid_tgid():获取当前进程ID和线程ID
    • bpf_get_current_uid_gid():获取当前用户ID和组ID
    • bpf_get_current_cgroup_id():获取当前cgroup ID
    • bpf_get_current_ancestor_cgroup_id():获取祖先cgroup ID
  • manipute network packets and forwarding logic:

    • bpf_skb_load_bytes()/bpf_skb_store_bytes():读取/修改数据包内容
    • bpf_l3_csum_replace()/bpf_l4_csum_replace():更新校验和
    • bpf_clone_redirect():克隆并重定向数据包
    • bpf_redirect():直接重定向数据包
    • bpf_skb_adjust_room():调整数据包空间

Tail&Function Call

概述: ebpf程序可以通过尾部调用和函数调用的概念进行组合,

  • 函数调用:允许ebpf程序中定义和调用函数
  • 尾调用:可以调用并执行另一个ebpf程序,并替换执行上下文,类似于execve()系统调用对常规进程的操作方式。

Tail Call

概述: 内核栈是很宝贵的,尾调用最大的优势就是其复用了当前栈帧并跳转至另外一个ebpf程序

ebpf程序都是独立验证的(调用者的对战和寄存器中的值被调用者不可访问),所以状态的传递一般可以使用per-cpu map传递

堆栈槽(slot)

概述: 指的是ebpf程序用于存储局部变量和临时数据的内存区域。BPF 程序拥有一个大小为 512 字节的固定堆栈空间,由特殊寄存器 R10 指向堆栈的顶部(高地址)。程序通过对 R10 进行负偏移来访问堆栈,例如 r10 - 8 表示堆栈顶部向下偏移 8 字节的位置。

开发工具链

bcc

概述: 使用户能够编写嵌入了ebpf程序的python程序,该框架主要针对涉及应用程序和系统分析跟踪的用例,其中ebpf程序用于收集统计数据或生成事件,而用户空间对应的程序收集数据并以人类可读的形式显示。运行该python程序会生成ebpf字节码并加载到内核中

bpftrace

概述: 是一种适用于linuc ebpf的高级跟踪语言,可用于半更新的linux内核(4.x)。bpftrace使用llvm作为后端将脚本编译为ebpf字节码,并利用bcc与linux ebpf子系统以及现有的linux跟踪功能进行交互:内核动态跟踪(kprobes)、用户级动态跟踪(uprobes)和跟踪点。

ebpf go library

概述: cilium社区开发了一个ebpf go library,作为通用的ebpf库,它将获取ebpf字节码的过程与ebpf程序的加载和管理解藕。ebpf程序通常是通过编写更高级的语言(比如go)来创建的,然后使用clang/llvm编译器编译为ebpf字节码

libbpf c/c++ library

概述: 是一个基于c/c++的通用ebpf库,它有助于clang/llvm编译器生成的ebpf目标文件加载到内核中,并且通过为应用程序提供易于使用的库API来抽象与bpf系统调用的交互

http://www.xdnf.cn/news/7376.html

相关文章:

  • Visual Studio解决方案构建三剑客:生成/重新生成/清理完全指南(实战经验总结)
  • 60天python训练计划----day30
  • GloVe 模型讲解与实战
  • 淘宝商品详情PAI接口可以获取哪些信息?
  • 人工智能重塑医疗健康:从辅助诊断到个性化治疗的全方位变革
  • React 个人笔记 Hooks编程
  • android双屏之副屏待机显示图片
  • leetcode 每日一题 1931. 用三种不同颜色为网格涂色
  • autoDL算力云装Xinference[坑与步骤]
  • JDK 21新特性详解
  • 网络学习-epoll(四)
  • lowcoder数据库操作5:使用饼图显示多个数据查询
  • 羽毛球订场小程序源码介绍
  • 数据库(一):分布式数据库
  • Java 反射(Reflection)技术
  • linux安装git
  • 二叉树-模版题单
  • 使用tcs34725传感器和51单片机识别颜色
  • git仓库中.git 文件很大,怎么清理掉一部分
  • 国标GB28181视频平台EasyGBS校园监控方案:多场景应用筑牢安全防线,提升管理效能
  • 【学习笔记】机器学习(Machine Learning) | 第七章|神经网络(2)
  • Rust 学习笔记:错误处理
  • Web 技术与 Nginx 网站环境部署
  • Pycharm 选择Python Interpreter
  • 酒水饮料批发零售商城小程序开发
  • 深入浅出程序设计竞赛(洛谷基础篇) 第十三章 二分查找与二分答案
  • 小米MUJIA智能音频眼镜来袭
  • 如何查看 Ubuntu开机是否需要密码
  • 一键启动多个 Chrome 实例并自动清理的 Bash 脚本分享!
  • 视图+触发器+临时表+派生表