2024年Go最新eBPF学习 - 入门(1),2024年最新Golang学习路线指南

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

    ^

3 warnings generated.
TIME(s) COMM PID FILE
0.000000000 b’node’ 1429 b’/root/.vscode-server/data/User/workspaceStorage/f610d604c637ea4c98b5ca477b61ef94/vscode.lock’
0.013446614 b’node’ 1265 b’/proc/6209/cmdline’
0.191411986 b’node’ 1421 b’/proc/meminfo’


## eBPF工作原理


eBPF是一个运行在内核的虚拟机,为了确保在内核中安全地执行,eBPF 只提供了非常有限的指令集。这些指令集可用于完成一部分内核的功能,但却远不足以模拟完整的计算机。为了更高效地与内核进行交互,eBPF 指令还有意采用了 C 调用约定,其提供的辅助函数可以在 C 语言中直接调用,极大地方便了 eBPF 程序的开发。eBPF运行时内部结构如图,主要由5大模块组成


* 第一个模块是eBPF 辅助函数。它提供了一系列用于 eBPF 程序与内核其他模块进行交互的函数。这些函数并不是任意一个 eBPF 程序都可以调用的,具体可用的函数集由 BPF 程序类型决定。
* 第二个模块是 eBPF 验证器。它用于确保 eBPF 程序的安全。验证器会将待执行的指令创建为一个有向无环图(DAG),确保程序中不包含不可达指令;接着再模拟指令的执行过程,确保不会执行无效指令。
* 第三个模块是由 11 个 64 位寄存器、一个程序计数器和一个 512 字节的栈组成的存储模块。这个模块用于控制 eBPF 程序的执行。其中,R0 寄存器用于存储函数调用和 eBPF 程序的返回值,这意味着函数调用最多只能有一个返回值;R1-R5 寄存器用于函数调用的参数,因此函数调用的参数最多不能超过 5 个;而 R10 则是一个只读寄存器,用于从栈中读取数据。
* 第四个模块是即时编译器,它将 eBPF 字节码编译成本地机器指令,以便更高效地在内核中执行。
* 第五个模块是 BPF 映射(map),它用于提供大块的存储。这些存储可被用户空间程序用来进行访问,进而控制 eBPF 程序的运行状态。


![image.png](https://img-blog.csdnimg.cn/img\_convert/49115ab566bc7336d0cbbd4149fdbaba.png#clientId=u441bcb81-25ff-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u73987dec&margin=[object Object]&name=image.png&originHeight=503&originWidth=915&originalType=url&ratio=1&rotation=0&showTitle=false&size=302847&status=done&style=none&taskId=u6042e61e-f352-4bc6-8bf6-6eaa05ab7df&title=)


## bpftool


Linux内核在4.15之后添加了bpftool这个工具可以用来查看和操作BPF对象,包括BPF程序和对应的映射表。它的源码位于Linux源代码的tools/bpf/bpftool中


### 命令简述


bpftool由对象和命令组成,在内核5.13中bpftool的对象包括 prog | map | link | cgroup | perf | net | feature | btf | gen | struct\_ops | iter  
 选项支持:


* -j、–json
* -p、–pretty
* -f、–bpffs
* -m、–mapcompat
* -n、-nomount



bpftool [OPTIONS] OBJECT {COMMAND | help}


对于每一类对象都有一个帮助文档,比如



bpftool prog help

Usage: /usr/lib/linux-tools/5.13.0-39-generic/bpftool prog { show | list } [PROG]
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog dump xlated PROG [{ file FILE | opcodes | visual | linum }]
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog dump jited PROG [{ file FILE | opcodes | linum }]
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog pin PROG FILE
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog { load | loadall } OBJ PATH
[type TYPE] [dev NAME]
[map { idx IDX | name NAME } MAP]
[pinmaps MAP_DIR]
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog attach PROG ATTACH_TYPE [MAP]
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog detach PROG ATTACH_TYPE [MAP]
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog run PROG
data_in FILE
[data_out FILE [data_size_out L]]
[ctx_in FILE [ctx_out FILE [ctx_size_out M]]]
[repeat N]
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog profile PROG [duration DURATION] METRICs
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog tracelog
/usr/lib/linux-tools/5.13.0-39-generic/bpftool prog help

   MAP := { id MAP_ID | pinned FILE | name MAP_NAME }
   PROG := { id PROG_ID | pinned FILE | tag PROG_TAG | name PROG_NAME }
   TYPE := { socket | kprobe | kretprobe | classifier | action |
             tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |
             cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |
             lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |
             sk_reuseport | flow_dissector | cgroup/sysctl |
             cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |
             cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |
             cgroup/getpeername4 | cgroup/getpeername6 |
             cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |
             cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |
             cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |
             struct_ops | fentry | fexit | freplace | sk_lookup }
   ATTACH_TYPE := { msg_verdict | stream_verdict | stream_parser |
                    flow_dissector }
   METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }
   OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} |
            {-m|--mapcompat} | {-n|--nomount} }

### bpftool perf


perf子命令用来显示哪些BPF程序正在通过`perf_event_open`进行挂载。



bpftool perf

pid 16377 fd 5: prog_id 32 kprobe func do_sys_openat2 offset 0


### bpftool prog show


bpftool prog show会列出所有的程序



bpftool prog show

3: cgroup_device tag e3dbd137be8d6168 gpl
loaded_at 2022-04-17T08:33:56+0000 uid 0
xlated 504B jited 309B memlock 4096B
4: cgroup_skb tag 6deef7357e7b4530 gpl
loaded_at 2022-04-17T08:33:56+0000 uid 0
xlated 64B jited 54B memlock 4096B
5: cgroup_skb tag 6deef7357e7b4530 gpl
loaded_at 2022-04-17T08:33:56+0000 uid 0
xlated 64B jited 54B memlock 4096B
6: cgroup_device tag 0ecd07b7b633809f gpl
loaded_at 2022-04-17T08:34:00+0000 uid 0
xlated 496B jited 307B memlock 4096B
7: cgroup_skb tag 6deef7357e7b4530 gpl
loaded_at 2022-04-17T08:34:00+0000 uid 0
xlated 64B jited 54B memlock 4096B
8: cgroup_skb tag 6deef7357e7b4530 gpl
loaded_at 2022-04-17T08:34:00+0000 uid 0
xlated 64B jited 54B memlock 4096B
9: cgroup_device tag ee0e253c78993a24 gpl
loaded_at 2022-04-17T08:34:04+0000 uid 0
xlated 416B jited 255B memlock 4096B
10: cgroup_device tag e3dbd137be8d6168 gpl
loaded_at 2022-04-17T08:34:06+0000 uid 0
xlated 504B jited 309B memlock 4096B
11: cgroup_device tag c8b47a902f1cc68b gpl
loaded_at 2022-04-17T08:34:06+0000 uid 0
xlated 464B jited 288B memlock 4096B
12: cgroup_device tag 8b9c33f36f812014 gpl
loaded_at 2022-04-17T08:34:08+0000 uid 0
xlated 744B jited 447B memlock 4096B
13: cgroup_skb tag 6deef7357e7b4530 gpl
loaded_at 2022-04-17T08:34:08+0000 uid 0
xlated 64B jited 54B memlock 4096B
14: cgroup_skb tag 6deef7357e7b4530 gpl
loaded_at 2022-04-17T08:34:08+0000 uid 0
xlated 64B jited 54B memlock 4096B
32: kprobe name hello_world tag 38dd440716c4900f gpl
loaded_at 2022-04-17T11:09:18+0000 uid 0
xlated 104B jited 70B memlock 4096B
btf_id 66


### bpftool prog dump xlated


xlated将BPF指令翻译为汇编指令打印出来。



bpftool prog dump xlated id 32

int hello_world(void * ctx):
; int hello_world(void *ctx)
0: (b7) r1 = 33
; ({ char fmt[] = “Hello, World!”; bpf_trace_printk(_fmt, sizeof(_fmt)); });
1: (6b) *(u16 *)(r10 -4) = r1
2: (b7) r1 = 1684828783
3: (63) *(u32 *)(r10 -8) = r1
4: (18) r1 = 0x57202c6f6c6c6548
6: (7b) *(u64 *)(r10 -16) = r1
7: (bf) r1 = r10
;
8: (07) r1 += -16
; ({ char fmt[] = “Hello, World!”; bpf_trace_printk(_fmt, sizeof(_fmt)); });
9: (b7) r2 = 14
10: (85) call bpf_trace_printk#-61904
; return 0;
11: (b7) r0 = 0
12: (95) exit


正是我们前面写的 C 代码,而其他行则是具体的 BPF 指令。具体每一行的 BPF 指令又分为三部分:


* 第一部分,冒号前面的数字 0-12 ,代表 BPF 指令行数;
* 第二部分,括号中的 16 进制数值,表示 BPF 指令码。它的具体含义你可以参考 [IOVisor BPF 文档](https://bbs.csdn.net/topics/618658159),比如第 0 行的 0xb7 表示为 64 位寄存器赋值。
* 第三部分,括号后面的部分,就是 BPF 指令的伪代码。


## BPF系统调用


在用户态与内核进行交互必须要使用系统调用来完成,在eBPF程序中使用的[系统调用](https://bbs.csdn.net/topics/618658159)



// cmd代表操作命令,比如BPF_PROG_LOAD是加载eBPF程序
// attr代表bpf_attr类型的eBPF属性指针,不同类型的操作命令需要传入不同的属性参数
// size代表属性的大小
int bpf(int cmd, union bpf_attr *attr, unsigned int size);


在内核5.13中已经支持了以下命令



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\_MAP\_CREATE | 创建一个BPF映射 |
| BPF\_MAP\_LOOKUP\_ELEM |  |


BPF\_MAP\_UPDATE\_ELEM  
 BPF\_MAP\_DELETE\_ELEM  
 F\_MAP\_LOOKUP\_AND\_DELETE\_ELEM  
 BPF\_MAP\_GET\_NEXT\_KEY | BPF映射相关的操作命令 |  
 | BPF\_PROG\_LOAD | 验证并加载BPF程序 |  
 | BPF\_PROG\_ATTACH  
 BPF\_PROG\_DETACH | 挂载/协助BPF程序 |  
 | BPF\_OBJ\_PIN | 把BPF程序或映射挂载到sysfs中的/sys/fs/bpf目录中 |  
 | BPF\_OBJ\_GET | 从/sys/fs/bpf目录中从查找BPF程序 |  
 | BPF\_BTF\_LOAD | 验证并加载BTF信息 |


## BPF辅助函数


eBPF 程序并不能随意调用内核函数,因此,内核定义了一系列的辅助函数,用于 eBPF 程序与内核其他模块进行交互。比如 bpf\_trace\_printk() 就是最常用的一个辅助函数,用于向调试文件系统(/sys/kernel/debug/tracing/trace\_pipe)写入调试信息。  
 eBPF 内部的内存空间只有寄存器和栈。所以,要访问其他的内核空间或用户空间地址,就需要借助 bpf\_probe\_read 这一系列的辅助函数。这些函数会进行安全性检查,并禁止缺页中断的发生。  
 而在 eBPF 程序需要大块存储时,就不能像常规的内核代码那样去直接分配内存了,而是必须通过 BPF 映射(BPF Map)来完成。  
 并不是所有的辅助函数都可以在 eBPF 程序中随意使用,不同类型的 eBPF 程序所支持的辅助函数是不同的。比如,对于 Hello World 示例这类内核探针(kprobe)类型的 eBPF 程序,你可以在命令行中执行 bpftool feature probe ,来查询当前系统支持的辅助函数列表:



bpftool feature probe

Scanning system configuration…
bpf() syscall restriction has unknown value 2
JIT compiler is enabled
JIT compiler hardening is disabled
JIT compiler kallsyms exports are enabled for root
Global memory limit for JIT compiler for unprivileged users is 264241152 bytes
CONFIG_BPF is set to y
CONFIG_BPF_SYSCALL is set to y
CONFIG_HAVE_EBPF_JIT is set to y
CONFIG_BPF_JIT is set to y
CONFIG_BPF_JIT_ALWAYS_ON is set to y
CONFIG_DEBUG_INFO_BTF is set to y
CONFIG_DEBUG_INFO_BTF_MODULES is set to y
CONFIG_CGROUPS is set to y
CONFIG_CGROUP_BPF is set to y
CONFIG_CGROUP_NET_CLASSID is set to y
CONFIG_SOCK_CGROUP_DATA is set to y
CONFIG_BPF_EVENTS is set to y
CONFIG_KPROBE_EVENTS is set to y
CONFIG_UPROBE_EVENTS is set to y
CONFIG_TRACING is set to y
CONFIG_FTRACE_SYSCALLS is set to y
CONFIG_FUNCTION_ERROR_INJECTION is set to y
CONFIG_BPF_KPROBE_OVERRIDE is set to y
CONFIG_NET is set to y
CONFIG_XDP_SOCKETS is set to y
CONFIG_LWTUNNEL_BPF is set to y
CONFIG_NET_ACT_BPF is set to m
CONFIG_NET_CLS_BPF is set to m
CONFIG_NET_CLS_ACT is set to y
CONFIG_NET_SCH_INGRESS is set to m
CONFIG_XFRM is set to y
CONFIG_IP_ROUTE_CLASSID is set to y
CONFIG_IPV6_SEG6_BPF is set to y
CONFIG_BPF_LIRC_MODE2 is not set
CONFIG_BPF_STREAM_PARSER is set to y
CONFIG_NETFILTER_XT_MATCH_BPF is set to m
CONFIG_BPFILTER is set to y
CONFIG_BPFILTER_UMH is set to m
CONFIG_TEST_BPF is set to m
CONFIG_HZ is set to 250

Scanning system call availability…
bpf() syscall is available

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
eBPF program_type lwt_xmit is available
eBPF program_type sock_ops is available
eBPF program_type sk_skb is available
eBPF program_type cgroup_device is available
eBPF program_type sk_msg is available
eBPF program_type raw_tracepoint is available
eBPF program_type cgroup_sock_addr is available
eBPF program_type lwt_seg6local is available
eBPF program_type lirc_mode2 is NOT available
eBPF program_type sk_reuseport is available
eBPF program_type flow_dissector is available
eBPF program_type cgroup_sysctl is available
eBPF program_type raw_tracepoint_writable is available
eBPF program_type cgroup_sockopt is available
eBPF program_type tracing is NOT available
eBPF program_type struct_ops is available
eBPF program_type ext is NOT available
eBPF program_type lsm is NOT available
eBPF program_type sk_lookup is available

Scanning eBPF map types…


## BPF映射


BPF 映射用于提供大块的键值存储,这些存储可被用户空间程序访问,进而获取 eBPF 程序的运行状态。eBPF 程序最多可以访问 64 个不同的 BPF 映射,并且不同的 eBPF 程序也可以通过相同的 BPF 映射来共享它们的状态。  
 创建BPF映射的最直接方法是使用bpf系统调用。如果该系统调用的第一个参数设置为BPF\_MAP\_CREATE,则表示创建一个新的映射。该调用将返回与创建映射相关的文件描述符。bpf系统调用的第二个参数是BPF映射的设置,如下所示:



union bpf_attr {
struct {
__u32 map_type;
__u32 key_size;
__u32 value_size;
__u32 max_entries;
__u32 map_flags;
};
}


其中最关键的是映射的类型,在内核头文件 include/uapi/linux/bpf.h 中的 bpf\_map\_type 定义了所有支持的映射类型,你可以使用如下的 bpftool 命令,来查询当前系统支持哪些映射类型:



bpftool feature probe | grep map_type

eBPF map_type hash is available
eBPF map_type array is available
eBPF map_type prog_array is available
eBPF map_type perf_event_array is available
eBPF map_type percpu_hash is available
eBPF map_type percpu_array is available
eBPF map_type stack_trace is available
eBPF map_type cgroup_array is available
eBPF map_type lru_hash is available
eBPF map_type lru_percpu_hash is available
eBPF map_type lpm_trie is available
eBPF map_type array_of_maps is available
eBPF map_type hash_of_maps is available
eBPF map_type devmap is available
eBPF map_type sockmap is available
eBPF map_type cpumap is available
eBPF map_type xskmap is available
eBPF map_type sockhash is available
eBPF map_type cgroup_storage is available
eBPF map_type reuseport_sockarray is available
eBPF map_type percpu_cgroup_storage is available
eBPF map_type queue is available
eBPF map_type stack is available
eBPF map_type sk_storage is available
eBPF map_type devmap_hash is available
eBPF map_type struct_ops is NOT available
eBPF map_type ringbuf is available
eBPF map_type inode_storage is available
eBPF map_type task_storage is available

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

ilable
eBPF map_type ringbuf is available
eBPF map_type inode_storage is available
eBPF map_type task_storage is available

[外链图片转存中…(img-INEMmvmq-1715630843499)]
[外链图片转存中…(img-NfEK9C5x-1715630843500)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值