eBPF理解

Posted 为了维护世界和平_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了eBPF理解相关的知识,希望对你有一定的参考价值。

目录

一、编程接口

二、命令码的类型

BPF辅助函数

三、BPF映射

四、程序的分类

跟踪类

网络类

1、XDP程序

2、TC程序

3、套接字程序

4、cgroup程序

其他eBPF程序


一、编程接口


#include <linux/bpf.h>

int bpf(int cmd, union bpf_attr *attr, unsigned int size);

cmd 类型,attr属性(map)

本文围绕类型,属性(映射),以及程序的分类进行介绍

二、命令码的类型

include/uapi/linux/bpf.h内核头文件中定义


enum bpf_cmd 
  BPF_MAP_CREATE,
  BPF_MAP_LOOKUP_ELEM,
  BPF_MAP_UPDATE_ELEM,
  BPF_MAP_DELETE_ELEM,
  BPF_MAP_GET_NEXT_KEY,
  BPF_PROG_LOAD,
  BPF_OBJ_PIN,
  BPF_OBJ_GET,
  BPF_PROG_ATTACH,
  BPF_PROG_DETACH,
  BPF_PROG_TEST_RUN,
  BPF_PROG_GET_NEXT_ID,
  BPF_MAP_GET_NEXT_ID,
  BPF_PROG_GET_FD_BY_ID,
  BPF_MAP_GET_FD_BY_ID,
  BPF_OBJ_GET_INFO_BY_FD,
  BPF_PROG_QUERY,
  BPF_RAW_TRACEPOINT_OPEN,
  BPF_BTF_LOAD,
  BPF_BTF_GET_FD_BY_ID,
  BPF_TASK_FD_QUERY,
  BPF_MAP_LOOKUP_AND_DELETE_ELEM,
  BPF_MAP_FREEZE,
  BPF_BTF_GET_NEXT_ID,
  BPF_MAP_LOOKUP_BATCH,
  BPF_MAP_LOOKUP_AND_DELETE_BATCH,
  BPF_MAP_UPDATE_BATCH,
  BPF_MAP_DELETE_BATCH,
  BPF_LINK_CREATE,
  BPF_LINK_UPDATE,
  BPF_LINK_GET_FD_BY_ID,
  BPF_LINK_GET_NEXT_ID,
  BPF_ENABLE_STATS,
  BPF_ITER_CREATE,
  BPF_LINK_DETACH,
  BPF_PROG_BIND_MAP,
;

BPF辅助函数

可以查询辅助函数

# bpftool feature probe
...
eBPF helpers supported for program type socket_filter:
	- bpf_map_lookup_elem
	- bpf_map_update_elem
	- bpf_map_delete_elem
	- bpf_ktime_get_ns
	- bpf_get_prandom_u32
	- bpf_get_smp_processor_id
	- bpf_tail_call
	- bpf_perf_event_output
	- bpf_skb_load_bytes
...

使用man bpf-helpers或者在内核源码bpf辅助函数中,可以查看其使用说明


三、BPF映射

BPF映射用于提供大块的键值存储,这些存储可被用户空间程序访问,进而获取 eBPF 程序的运行状态。 在eBPF 程序需要大块存储时,就不能像常规的内核代码那样去分配内存了,而是必须通过 BPF 映射(BPF Map)来完成。

bpf_map_type 类型在内核源码 include/uapi/linux/bpf.h

enum bpf_map_type 
	BPF_MAP_TYPE_UNSPEC,
	BPF_MAP_TYPE_HASH,
	BPF_MAP_TYPE_ARRAY,
	BPF_MAP_TYPE_PROG_ARRAY,
	BPF_MAP_TYPE_PERF_EVENT_ARRAY,
	BPF_MAP_TYPE_PERCPU_HASH,
	BPF_MAP_TYPE_PERCPU_ARRAY,
	BPF_MAP_TYPE_STACK_TRACE,
	BPF_MAP_TYPE_CGROUP_ARRAY,
	BPF_MAP_TYPE_LRU_HASH,
	BPF_MAP_TYPE_LRU_PERCPU_HASH,
	BPF_MAP_TYPE_LPM_TRIE,
	BPF_MAP_TYPE_ARRAY_OF_MAPS,
	BPF_MAP_TYPE_HASH_OF_MAPS,
	BPF_MAP_TYPE_DEVMAP,
	BPF_MAP_TYPE_SOCKMAP,
	BPF_MAP_TYPE_CPUMAP,
	BPF_MAP_TYPE_XSKMAP,
	BPF_MAP_TYPE_SOCKHASH,
	BPF_MAP_TYPE_CGROUP_STORAGE,
	BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
	BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
	BPF_MAP_TYPE_QUEUE,
	BPF_MAP_TYPE_STACK,
	BPF_MAP_TYPE_SK_STORAGE,
	BPF_MAP_TYPE_DEVMAP_HASH,
	BPF_MAP_TYPE_STRUCT_OPS,
	BPF_MAP_TYPE_RINGBUF,
	BPF_MAP_TYPE_INODE_STORAGE,
	BPF_MAP_TYPE_TASK_STORAGE,
;

通过以下代码创建一个BPF映射,通过用户态程序的系统调用来创建


int bpf_create_map(enum bpf_map_type map_type,
       unsigned int key_size,
       unsigned int value_size, unsigned int max_entries)

  union bpf_attr attr = 
    .map_type = map_type,
    .key_size = key_size,
    .value_size = value_size,
    .max_entries = max_entries
  ;
  return bpf(BPF_MAP_CREATE, &attr, sizeof(attr));

如果eBPF程序使用了BCC库,可以使用预定义的宏简化BPF的映射创建


四、程序的分类

bpf_prog_type 

enum bpf_prog_type 
	BPF_PROG_TYPE_UNSPEC,
	BPF_PROG_TYPE_SOCKET_FILTER,
	BPF_PROG_TYPE_KPROBE,
	BPF_PROG_TYPE_SCHED_CLS,
	BPF_PROG_TYPE_SCHED_ACT,
	BPF_PROG_TYPE_TRACEPOINT,
	BPF_PROG_TYPE_XDP,
	BPF_PROG_TYPE_PERF_EVENT,
	BPF_PROG_TYPE_CGROUP_SKB,
	BPF_PROG_TYPE_CGROUP_SOCK,
	BPF_PROG_TYPE_LWT_IN,
	BPF_PROG_TYPE_LWT_OUT,
	BPF_PROG_TYPE_LWT_XMIT,
	BPF_PROG_TYPE_SOCK_OPS,
	BPF_PROG_TYPE_SK_SKB,
	BPF_PROG_TYPE_CGROUP_DEVICE,
	BPF_PROG_TYPE_SK_MSG,
	BPF_PROG_TYPE_RAW_TRACEPOINT,
	BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
	BPF_PROG_TYPE_LWT_SEG6LOCAL,
	BPF_PROG_TYPE_LIRC_MODE2,
	BPF_PROG_TYPE_SK_REUSEPORT,
	BPF_PROG_TYPE_FLOW_DISSECTOR,
	BPF_PROG_TYPE_CGROUP_SYSCTL,
	BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
	BPF_PROG_TYPE_CGROUP_SOCKOPT,
	BPF_PROG_TYPE_TRACING,
	BPF_PROG_TYPE_STRUCT_OPS,
	BPF_PROG_TYPE_EXT,
	BPF_PROG_TYPE_LSM,
	BPF_PROG_TYPE_SK_LOOKUP,
;

也可以使用

bpftool feature probe | grep program_type 

应用程序类型大致可以分为三类

1,跟踪,从内核和程序的运行状态中提取跟踪信息

2,网络,对网络数据包进行过滤和处理

3、其他,安全,BPF扩展

跟踪类

主要用于从系统中提取跟踪信息,为监控、排错,性能优化提供数据支撑;

程序的类型有

类型描述
BPF_PROG_TYPE_KPROBE用于对特定函数进行插装kprobe,uprobe
BPF_PROG_TYPE_TRACEPOINT用于内核静态跟踪点
BPF_PROG_TYPE_PERF_EVENT用于性能事件跟踪,内核调用,定时器,硬件等

网络类

主要用于对网络数据包进行过滤和处理,进而实现网络的观测、过滤、流量控制等功能

又可分为XDP,TC,套接字和cgroup程序

1、XDP程序

        类型 :BPF_PROG_TYPE_XDP

        在网络驱动程序刚收到数据包时触发,无需通过网络协议栈,可用来实现高性能网络处理方案,常用于DDos防御,防火墙,4层负载均衡等场景。

        XDP程序在处理网络包后,有不同处理方式

命令码含义使用场景
XDP_DROP丢包防火墙,DDOS攻击防御
XDP_PASS传递到内核协议栈正常处理

XDP_TX

XDP_REDIRECT

转发到同一/不同网卡负载均衡
XDP_ABORTED错误XDP处理错误

命令行使用

# eth1 为网卡名
# xdpgeneric 设置运行模式为通用模式
# xdp-example.o 为编译后的 XDP 字节码
sudo ip link set dev eth1 xdpgeneric object xdp-example.o



#卸载
sudo ip link set veth1 xdpgeneric off

BCC库函数

from bcc import BPF

# 编译XDP程序
b = BPF(src_file="xdp-example.c")
fn = b.load_func("xdp-example", BPF.XDP)

# 加载XDP程序到eth0网卡
device = "eth0"
b.attach_xdp(device, fn, 0)

...

# 卸载XDP程序
b.remove_xdp(device)

2、TC程序

类型:BPF_PROG_TYPE_SCHED_CLS 和 BPF_PROG_TYPE_SCHED_ACT

分别作为 Linux 流量控制 的分类器和执行器,Linux 流量控制通过网卡队列、排队规则、分类器、过滤器以及执行器等,实现了对网络流量的整形调度和带宽控制。

TC可以直接获取内核解析后的网络报文数据结构sk_buff,可以在发送和接收两个方向上执行

  1. 接收网络包,TC程序在网卡接收(GRO)之后、协议栈处理之前
  2. 发送网络包,TC乘坐在协议栈处理之后,数据包发送到网卡队列之前(GOS)执行
# 创建 clsact 类型的排队规则
sudo tc qdisc add dev eth0 clsact

# 加载接收方向的 eBPF 程序
sudo tc filter add dev eth0 ingress bpf da obj tc-example.o sec ingress

# 加载发送方向的 eBPF 程序
sudo tc filter add dev eth0 egress bpf da obj tc-example.o sec egress

Traffic Control HOWTO (linux-ip.net)

3、套接字程序

        用于过滤,观测或重定向套接字网络包。

        可以挂载到套接字socket,控制组cgroup以及网络命名空间netns等位置

        类型以及说明

类型说明

BPF_PROG_TYPE_SOCKET_FILTER

套接字过滤和观测

BPF_PROG_TYPE_SOCK_OPS

套接字修改重定向

BPF_PROG_TYPE_SK_SKB

用于套接字修改或消息流动态解析

BPF_PROG_TYPE_SK_MSG

用于控制内核是否发送消息套解析

BPF_PROG_TYPE_SK_REUSEPORT

控制端口是否重用
BPF_PROG_TYPE_SK_LOOKUP用于TCP连接选择监听套接字或为UDP数据包选择未连接的套接字,绕过bind系统调用

使用例子第一条如:用户态 setsockopt(sock,SOL_SOCKET,SO_ATTACH_BPF,...)绑定BPF到具体的socket上。

4、cgroup程序

        对cgroup内所有的进程的网络过滤、套接字选项以及转发等进行动态控制

        典型用在容器中多进程进行网络控制

        类型及说明

类型说明
BPF_PROG_TYPE_CGROUP_SKB    在入口和出口过滤包,并可以接收或拒绝数据包
BPF_PROG_TYPE_CGROUP_SOCK在套接字创建、释放和绑定地址时,接受或拒绝操作,也可用于统计套接字信息
BPF_PROG_TYPE_CGROUP_DEVICE对设备文件访问进行过滤
BPF_PROG_TYPE_CGROUP_SOCK_ADDR在connect,bind,sendto,recvmsg中修改IP地址和端口
BPF_PROG_TYPE_CGROUP_SYSCTL对设备文件访问过滤
BPF_PROG_TYPE_CGROUP_SOCKOPT在setsockopt和getsockopt操作中修改套接字

这些类型的BPF程序都可以通过BPF系统调用的BPF_PROG_ATTACH进行挂载。如

union bpf_attr attr = ;
attr.target_fd = target_fd;            // cgroup文件描述符
attr.attach_bpf_fd = prog_fd;          // BPF程序文件描述符
attr.attach_type = BPF_CGROUP_DEVICE;  // 挂载类型为BPF_CGROUP_DEVICE

if (bpf(BPF_PROG_ATTACH, &attr, sizeof(attr)) < 0) 
  return -errno;


...

其他eBPF程序

类型说明
BPF_PROG_TYPE_LSM  用于安全模块访问控制和审计策略
BPF_PROG_TYPE_LWT_IN,
BPF_PROG_TYPE_LWT_OUT,
BPF_PROG_TYPE_LWT_XMIT,
 用于轻量级的封装或解封装
BPF_PROG_TYPE_STRUCT_OPS  拥塞控制
BPF_PROG_TYPE_FLOW_DISSECTOR 流量解析器
BPF_PROG_TYPE_EXT 扩展程序

参考

bpf.h - include/uapi/linux/bpf.h - Linux source code (v5.13) - Bootlin

XDP - IO Visor Project

Traffic Control HOWTO (linux-ip.net)


以上是关于eBPF理解的主要内容,如果未能解决你的问题,请参考以下文章

eBPF理解

eBPF理解

eBPF理解

eBPF理解

eBPF理解

基于 eBPF 的 Kubernetes 可观测实践