关于bpf:eBPF-HashMap-与-padding-的坑

前言上一篇文章《ebpf-go 初体验》中,咱们提到了一个小插曲,就是当 map 的 key 这样写的时候 struct tuple key = {ip, bpf_ntohs(sport)},map 的 key 看起来会反复,有些令人惊讶,于是我用另外一台机器 B 测了下(内核 6.6,clang 14.0.0)。发现了报错:"invalid indirect read from stack R2 off",顺藤摸瓜找到了这篇文档1 ,才反馈过去:咱们的 struct tuple 是不规整的,须要 padding,而不同的架构/编译器对 padding 的解决又是一样的,从而导致了不同的后果。 那么这个 padding 到底是怎么导致看起来反复的 key 的呢?这就得看看 ebpf 的 hashmap 的实现原理了。 ebpf hashmap 外围原理bpf 的 map 的操作都在 syscall2 中,从其中的 map_update_elem 下手,找到 bpf_map_update_value,而后是 map->ops->map_update_elem,找到 hashmap 对应的实现就在此3(per cpu4 的咱们先不看),外围如下: static long htab_map_update_elem(struct bpf_map *map, void *key, void *value, u64 map_flags){ hash = htab_map_hash(key, key_size, htab->hashrnd); b = __select_bucket(htab, hash); head = &b->head; l_old = lookup_elem_raw(head, hash, key, key_size); l_new = alloc_htab_elem(htab, key, value, key_size, hash, false, false, l_old); /* add new element to the head of the list, so that * concurrent search will find it before old elem */ hlist_nulls_add_head_rcu(&l_new->hash_node, head);}如果你学过 Java 就晓得:一个 Objec 要能成为 hashmap 的 key,必须得有 hashcode 和 equals 办法。这也是hashmap 的外围,与语言无关。那么下面的代码如何体现的呢? ...

March 3, 2024 · 2 min · jiezi

关于bpf:TCP-连接延迟监视工具-tcpconnlat-分析-eBPF基础知识-Part5

基于 libbpf 的 TCP 连贯提早监督工具 tcpconnlat 剖析 - eBPF基础知识 Part5《eBPF基础知识》 系列简介: 《eBPF基础知识》系列指标是整顿一下 BPF 相干的基础知识。次要聚焦程序与内核互动接口局部。文章应用了 libbpf,但如果你不间接应用 libbpf,看本系列还是有肯定意义的,因为它聚焦于程序与内核互动接口局部,而非 libbpf 封装自身。而所有 bpf 开发框架,都要以类似的形式跟内核互动。甚至框架自身就是基于 libbpf。哪怕是 golang/rust/python/BCC/bpftrace。 《ELF 格局简述 - eBPF基础知识 Part1》《BPF 零碎接口 与 libbpf 示例剖析 - eBPF基础知识 Part2》《经典 libbpf 范例: bootstrap 剖析 - eBPF基础知识 Part3》《经典 libbpf 范例: uprobe 剖析 - eBPF基础知识 Part4》国内习惯:尽量多图少文字。以下假如读者曾经对 BPF 有肯定的理解,或者浏览过之前的 《eBPF基础知识》系列文章。 很少人晓得,eBPF 的利用鼻祖 BCC 除了提供很多基于 python/bpftrace 的工具集之外,最近因为 libbpf 1.0 大大加强了:易用性、性能、执行文件的可移植性 BPF CO-RE (Compile Once – Run Everywhere) 的起因,开始有很多间接用 libbpf 1.0 写的 c 的 工具了。其中一个就是这篇文章要讲的 tcpconnlat 。 ...

April 13, 2023 · 6 min · jiezi

关于bpf:经典-libbpf-范例-uprobe-分析-eBPF基础知识-Part4

经典 libbpf 范例: uprobe 剖析 - eBPF基础知识 Part4《eBPF基础知识》 系列简介: 《eBPF基础知识》系列指标是整顿一下 BPF 相干的基础知识。次要聚焦程序与内核互动接口局部。文章应用了 libbpf,但如果你不间接应用 libbpf,看本系列还是有肯定意义的,因为它聚焦于程序与内核互动接口局部,而非 libbpf 封装自身。而所有 bpf 开发框架,都要以类似的形式跟内核互动。甚至框架自身就是基于 libbpf。哪怕是 golang/rust/python/BCC/bpftrace。 《ELF 格局简述 - eBPF基础知识 Part1》《BPF 零碎接口 与 libbpf 示例剖析 - eBPF基础知识 Part2》《经典 libbpf 范例: bootstrap 剖析 - eBPF基础知识 Part3》国内习惯:尽量多图少文字。以下假如读者曾经对 BPF 有肯定的理解,或者浏览过之前的 《eBPF基础知识》系列文章。 libbpf 提供了一个应用 libbpf 的示例:https://github.com/libbpf/libbpf-bootstrap。其中的 uprobe 程序示范了一个最简略的 BPF uprobe 程序加载、绑定到 user space ELF 函数、与内核互动的过程。上面将图解剖析这个程序与内核的互动过程。 动机:为何我想学习 BPF uprobe开始剖析前,我想说几句废话:为何我想学习 BPF uprobe? 大部分利用的行为,都以函数为单元来划分,跟踪利用的函数是跟踪利用很好的切入点 例如我之前写的: 逆向工程与云原生现场剖析 Part1 —— eBPF 跟踪 Istio/Envoy 之学步逆向工程与云原生现场剖析 Part2 —— eBPF 跟踪 Istio/Envoy 之启动、监听与线程负载平衡逆向工程与云原生现场剖析 Part3 —— eBPF 跟踪 Istio/Envoy 事件驱动模型、连贯建设、TLS 握手与 filter_chain 抉择逆向工程与云原生现场剖析 Part4 —— eBPF 跟踪 Istio/Envoy 之 upstream/downstream 事件驱动合作下的 HTTP 反向代理流程stack 性能剖析 ...

April 4, 2023 · 6 min · jiezi

关于bpf:经典-bpf-范例-bootstrap-分析-eBPF基础知识-Part3

经典 libbpf 范例: bootstrap 剖析 - eBPF基础知识 Part3《eBPF基础知识》 系列简介: 《eBPF基础知识》系列指标是整顿一下 BPF 相干的基础知识。次要聚焦程序与内核互动接口局部。文章应用了 libbpf,但如果你不间接应用 libbpf,看本系列还是有肯定意义的,因为它聚焦于程序与内核互动接口局部,而非 libbpf 封装自身。而所有 bpf 开发框架,都要以类似的形式跟内核互动。甚至框架自身就是基于 libbpf。哪怕是 golang/rust/python/BCC/bpftrace。 《ELF 格局简述 - eBPF基础知识 Part1》《BPF 零碎接口 与 libbpf 示例剖析 - eBPF基础知识 Part2》上期 《BPF 零碎接口 与 libbpf 示例剖析 - eBPF基础知识 Part2》 介绍了一个最简的 BPF 程序如何与内核互动。 这期,将图解剖析一个更为事实的实用的 BPF 程序与内核的互动过程。国内习惯:尽量多图少文字。以下假如读者曾经对 BPF 有肯定的理解,或者浏览过之前的 《eBPF基础知识》系列文章。 libbpf 提供了一个应用 libbpf 的示例:https://github.com/libbpf/libbpf-bootstrap。其中的 bootstrap 程序示范了一个最简略但事实实用的 BPF 程序加载、运行、与内核互动的过程。上面将图解剖析这个程序与内核的互动过程。 动机:为何我想学习 BPF开始剖析前,我想说几句废话:为何我想学习 BPF? 因为是热点啊 :) 。看,当年的 Block-Chain、AI、CloudNative。现在的 ChatGPT。我抵赖,35 岁前的我真会这样思考问题。而且,如果让我带着当初的认知回到 35 岁前的身材上,说不定心底也会是这个答案。 但当初,我更想使用 BPF 来有个更深远的底层技术观察力: ...

March 26, 2023 · 4 min · jiezi

关于bpf:BPF-系统接口-与-libbpf-示例分析-eBPF基础知识-Part2

BPF 零碎接口 与 libbpf minimal 示例剖析 - eBPF基础知识如果你学习 eBPF。那么你不久就会发现,简直所有 eBPF 的架构,包含 BCC/bpftrace 在内,都在用户态应用了 libbpf 这个 helper lib。 from [BPF Performance Tools] - Brendan Gregg 在 BCC/bpftrace 刚衰亡之时, libbpf 还是个小 BB,API 形象有余,只能用作底层库,为 BCC/bpftrace 做脚手架。但当小 BB 倒退到 libbpf 1.0 时,状况有了变动。API 界面的形象和敌对水平减少了,加上人们开始对轻量化 BPF 运行条件,一次编译到处运行(BPF CO-RE) 的期待越来越高。 libbpf 开始备受关注。 而我集体想钻研 libbpf 的目标是想理解内核加载与运行 BPF 程序的接口和抽象概念。要理解内核如何形象 BPF 设计和概念,当然能够间接看源码。但我认为看 BPF 用户状与内核态的 API 设计,足以应答大部分需要。也比拟好管制方向不迷失。 同理,学习 libbpf 当然能够间接看原码。但时候,看设计者如何应用(调用)本人的源码,比间接看源码来得直观与快捷。一个例子胜过 N 个情理。 libbpf 提供了一个很好的,轻度应用 libbpf 的示例: https://github.com/libbpf/libbpf-bootstrap 上面以其中的 minimal 来阐明一个最简略的 BPF 程序加载与运行过程。 ...

March 12, 2023 · 5 min · jiezi

关于bpf:Datenlord-用BPF实现用户态tracing

BPF是最近Linux内核畛域热门的技术。传统的BPF指的是tcpdump命令用于过滤网络包的工具,当初BPF曾经失去极大的扩大,不再是Berkeley Packet Filter的缩写对应的简略的网络包过滤工具。 从Kernel 4.9之后,BPF曾经成为一个欠缺的内核扩大工具,BPF在内核里运行一个sandbox,用于执行BPF的字节码(bytecode), 在执行BPF程序前,BPF的查看器会对BPF程序的字节码进行安全检查(比方,指针要先判断不为空后再拜访,代码里不能有循环,等等),以保障BPF程序不会导致系统解体,因为BPF程序执行时是在内核态。 因而,BPF能够很平安地在内核态执行用户编写的程序,而且有平安保障,这比编写内核模块平安太多了。 正是因为BPF能保障平安,并运行在内核态,能够大大简化很多以前很简单的事件,目前BPF曾经利用于性能剖析、网络、平安、驱动、区块链等等畛域。 曾经有很多文章介绍BPF在内核性能剖析(Kernel tracing)方面的利用。内核有各种定义的tracepoint用于动态tracing,也能够采纳动静tracing来跟踪内核函数调用。 用BPF进行内核tracing,开销小而且性能好,因为BPF程序是运行在内核态,不须要把采集到的数据再传回用户态解决,而是间接在内核态实现数据采集和解决,而后把处理结果传回用户态用于展现。 对于BPF用于内核tracing方面不再赘述,本文专一于利用BPF进行用户态利用性能剖析(Userspace tracing)方面。 用户态tracing在进行用户态tracing前,要在程序里定义tracepoints。这里次要介绍Userland Statically Defined Tracepoints(USDT)。 因为USDT依赖systemtap-sdt-dev包,先要装置依赖包,以Ubuntu为例,运行sudo apt install systemtap-sdt-dev进行装置。 上面的示例test-server.c给出如何应用宏DTRACE_PROBE1在用户程序里定义tracepoint: #include <sys/sdt.h>#include <unistd.h>int main(int argc, char **argv){ int idx = 0; while(1) { idx++; // 自定义的tracepoint DTRACE_PROBE1(test_grp, test_idx, idx); sleep(1); } return 0;}下面的例子,用宏DTRACE_PROBE1定义了一个组名为test_grp、名称为test_idx的用户态tracepoint。该tracepoint只有一个参数,该参数是一个递增的整数变量。 如果要定义有两个或更多参数的tracepoint,要用DTRACE_PROBE2、DTRACE_PROBE3,以此类推。如果tracepoint不带参数,则用DTRACE_PROBE来定义。 用gcc命令编译下面的程序gcc -g -fno-omit-frame-pointer -O0 test-server.c -o test-server,失去可执行的二进制程序test-server。 USDT的原理用宏DTRACE_PROBE1定义的tracepoint在编译实现的二进制里对应CPU指令nop操作,能够用gdb看下二进制文件test-server对应的汇编: $ gdb test-server......Reading symbols from test-server...(gdb) disas main <<== gdb命令用于查看二进制文件的汇编Dump of assembler code for function main: 0x0000000000001149 <+0>: endbr64 0x000000000000114d <+4>: push %rbp 0x000000000000114e <+5>: mov %rsp,%rbp 0x0000000000001151 <+8>: sub $0x20,%rsp 0x0000000000001155 <+12>: mov %edi,-0x14(%rbp) 0x0000000000001158 <+15>: mov %rsi,-0x20(%rbp) 0x000000000000115c <+19>: movl $0x0,-0x4(%rbp) 0x0000000000001163 <+26>: addl $0x1,-0x4(%rbp) 0x0000000000001167 <+30>: nop <<= tracepoint对应的nop指令 0x0000000000001168 <+31>: mov $0x1,%edi 0x000000000000116d <+36>: callq 0x1050 <sleep@plt> 0x0000000000001172 <+41>: jmp 0x1163 <main+26>End of assembler dump.从下面的汇编能够看出,nop操作只是放空一个CPU cycle,这个代价非常低,所以程序里定义USDT对性能的影响能够疏忽。 ...

July 21, 2022 · 2 min · jiezi

关于bpf:网络包的内核漂流记-Part-1-图解网络包接收流程

注,原文来自 https://blog.mygraphql.com/zh... 。如你看到的转载图片不清,请回到原文。 目录目录《网络包的内核漂流记》系列介绍 格调、款式、本文的交互浏览形式 ISO 网络模型网络包接管流程概述网络包接管步骤 初始化与配置IRQ 解决SoftIRQ 中加载网络包到内存SoftIRQ 中推送网络包到下层结尾相干《网络包的内核漂流记》系列介绍大家晓得,网络数据来源于网线、光纤、无线电波上的比特(bit),而后到网卡,到内核,最初到利用过程 socket。事件如同很简略。但如果是 SRE/DevOps 或是 Performance Engineer ,须要做粗疏的监控和优化时,这些显然是不够的。援用本文次要参考作者的原话: Optimizing and monitoring the network stack is impossible unless you carefully read and understand how it works. You cannot monitor code you don’t understand at a deep level.除非您仔细阅读并理解其工作原理,否则无奈优化和监控网络堆栈。 您无奈深刻监控您不了解的代码。—— Joe Damato《网络包的内核漂流记》尝试剖析和跟踪一个网络包在内核各子系统间的流转和触发的合作。 开始前先做个预报,《网络包的内核漂流记》 零碎(将)包含: Part 1: 图解网络包接管流程Part 2: BPF 跟踪网络包的内核漂流 我将演示如何用 bpftrace 踪网络包的内核漂流。为免吓跑人,还是老套路,多图少代码。不过有的图有点点简单。 本系列次要参考:Monitoring and Tuning the Linux Networking Stack: Receiving Data 。是的,这是篇被转载、参考到泛滥的文章。简直你能在网上找到的所有讲 Linux 网卡和网络栈收发的文章,都会参考它。但有句话是: ...

April 19, 2022 · 2 min · jiezi