BPF程序学习

一、介绍

历史:

cBPF:Linux 2.1.75 -> eBPF:Linux 3.18

eBPF能做什么呢?

 

二、编写BPF程序

BPF程序类型

bpf_prog_type 该类型定义在/include/uapi/linux/bpf.h。

enum bpf_prog_type {
    BPF_PROG_TYPE_UNSPEC,
    BPF_PROG_TYPE_SOCKET_FILTER,
    BPF_PROG_TYPE_KPROBE,           //用于内核动态插桩点kprobes
    BPF_PROG_TYPE_SCHED_CLS,        //用于流量控制分类
    BPF_PROG_TYPE_SCHED_ACT,
    BPF_PROG_TYPE_TRACEPOINT,       //用于内核静态跟踪点
    BPF_PROG_TYPE_XDP,             //用于XDP(eXpress Data Path)程序
    BPF_PROG_TYPE_PERF_EVENT,      //用于perf_events,包括PMC
    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,
    BPF_PROG_TYPE_SYSCALL, /* a program that can execute syscalls */
};

BPF存储类型

BPF程序之间数据通信或和用户程序交互通过存储映射来实现。BPF程序可以创建一个map来存储数据,它会在sys文件系统中保存,详细在/sys/fs/bpf/xdp/globals/该map名

enum bpf_map_type {
    BPF_MAP_TYPE_UNSPEC,
    BPF_MAP_TYPE_HASH,        //用于哈希表的Map类型:保存key/value 对
    BPF_MAP_TYPE_ARRAY,        //数组类型
    BPF_MAP_TYPE_PROG_ARRAY,
    BPF_MAP_TYPE_PERF_EVENT_ARRAY,   //到perf_event环形缓冲区的接口, 用于将记录发送到用户空间
    BPF_MAP_TYPE_PERCPU_HASH,       //一个基于每个CPU单独维护的更快哈希表
    BPF_MAP_TYPE_PERCPU_ARRAY,      //一个基于每个CPU单独维护的更快数组
    BPF_MAP_TYPE_STACK_TRACE,       //调用栈存储,使用栈ID进行索引
    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_MAP_TYPE_BLOOM_FILTER,
};

BPF辅助函数

BPF程序不能随意调用内核函数,内核专门提供了BPF可以调用的函数

bpf_map_lookup_elem(map, key) 在map中查找键值key,并返回它的值(指针)
bpf_map_delete_elem(map, key) 根据key值删除map中对应的元素
bpf_ktime_get_ns() 返回系统启动后的时长,单位ns
bpf_trace_printk(fmt, fmt_size, …) 向TraceFS的pipe文件中写入调试信息

 

三、存储类型map相关函数

1.bpf_map_lookup_elem函数

存在两种定义,分别来自不同的头文件。

  在"#include <linux/bpf.h>"中是:

通过键返回映像中该键对应的值,定义如下:

static void *(*bpf_map_lookup_elem)(struct bpf_map *map, void *key)

 

  在“#include <bpf/bpf.h>”中是:

查询映像中是否存在该键值对,查询结果返回到value中,定义如下:

LIBBPF_API int bpf_map_lookup_elem(int fd, const void *key, void *value)

 

2.bpf_obj_get函数

可从已固定的 /sys/fs/bpf 文件返回文件描述符。此文件描述符可用于进一步的操作,例如读取映射或将程序附加到跟踪点。

定义如下:

int bpf_obj_get(const char *pathname)

 

3.bpf_map_delete_elem函数

删除映像中对应键的键值对,定义如下:

#include <bpf/bpf.h>
LIBBPF_API int bpf_map_delete_elem(int fd, const void *key)

 

4.bpf_map_get_next_key函数

获取该键在映像顺序中的下一个键,定义如下:

LIBBPF_API int bpf_map_get_next_key(int fd, const void *key, void *next_key)

 

5.bpf_map_update_elem函数

更新或修改映像中的键值对,定义如下:

LIBBPF_API int bpf_map_update_elem(int fd, const void *key, const void *value, __u64 flags)

 

6.bpf_probe_read函数

将src的内容拷贝到dst中。内核对于非简单类型的赋值需要进行安全边界的检查,避免在内核中进行越界访问,破坏内核稳定性和安全性的保障。

定义如下:

#define BPF_PROBE_READ_INTO(dst, src, a, ...) ({                \
    ___core_read(bpf_probe_read, bpf_probe_read,                \
             dst, (src), a, ##__VA_ARGS__)                \
})

 

 

例如:bpf_probe_read(&tcpflags, sizeof(u8), thp)。

 

posted @ 2022-09-10 21:30  An2i  阅读(269)  评论(0编辑  收藏  举报