TGINSIGHT CHAT
Welcome to the Black Parade
@TheB1ackParade
MusicDeath has many faces, I look forward to seeing this one.
Recent posts
Page 47 of 76 · 907 posts
Posted Sep 25
前两周 ray 问我有什么入门 bpf 的推荐方法,我结合最近的实践给出以下几个练手项目: 1. 内核态观测:实现 pwru 简化版。本质来说就是扫描 btf,attach kprobe on all kfuncs with skb param,搜集 skb 数据,传回用户态。非常简单,我昨天亲自试了一下,半天就写完了。 2. 网络观测:tc/xdp-dump 是很简单的项目,相比上一个小项目,这个可以学会在 bpf 里解析网络流量,做一些基本的过滤,也比较简单。 3. 网络编程:我还是推荐 xdp-tutorial 项目,不过我们的要求要更高一点,要 from scratch 而不是填充式编程,而且要用 xdp 和 tc 分别实现。其实 lizrice 的 lb-from-scratch 也是一个不错的入门小项目,已经有 cilium standalone lb 的风味了。 4. 用户态观测:C 语言和 CPython 的 ftrace!由于他们的栈都是平铺直叙毫无幺蛾子,所以非常简单,前者用 uprobe + uretprobe,后者用 USDT。如果想进一步的话就去解析参数,C 的参数要解 dwarf,CPython 去解析 frame object,都是很好的 ELF 实践。 不走弯路,我推荐直接 cilium/ebpf 作为用户态 lib,虽然不如 libbpf 啥都支持,但是实现上述功能绰绰有余。
Posted Sep 19
虽然已经是两天前的事情了,但是以防大家还不知道:cilium 从 CNCF 毕业啦!虽然 bug 奇多无比,五个月给客户升级都升不上去,符合我对脚踏车的想象。
Posted Sep 14
最近高强度在百度贴吧摸鱼,被系统大量自动删帖,见识了新时代下的关键词系统,实在叹为观止,决定精选一些我被删除的发帖: 1. 留下你和桀圣的 onlyfans 链接 2. 推动超级小桀入脑、入心、入魂 3. 2012 纽约时报 4. 我愿称之为伟人 5. 您也是伟人 6. 412 反革命政变 7. 最大的可能是小学学历 8. hjt 9. 人民是历史创造者,人民是真正的英雄 10. 墙外互联网著名意见领袖 11. she总头一歪,说"for the union" 可见贴吧真理部也是精通各种梗,我比较惊讶的是“入脑入心入魂”这么新的梗居然都有收录,可见真理部内部也急需大清洗(
Posted Sep 12
给大家推荐一个弱智方法用来检查汇编的机器码。比如我想知道 incq %gs:0x10(%rcx) 被编成了啥,就可以运行 echo 'int main() { asm("incq %gs:0x10(%rcx)"); }' | gcc -xc - && gdb -q -ex 'disas/r main' -ex q ./a.out ,结果乳头。
Posted Sep 11
震撼,这玩意儿已经进化到开始拒绝写代码了。水平极差,脾气还大,气死!
Posted Sep 10
这简直是我见过的最离谱的事情:钢铁雄心4全成就 那我的小目标也确认了,是时候在美国建立君主制了。
Posted Sep 7
。。我竟然第一次知道 BASH_REMATCH ,太菜了。 图上的正则用的是大家比较少用的 [:alpha:] ,但其实也可以用更常见的模式,比如 $ version=v1.14.0-ce $ [[ $version =~ v([0-9])\.([0-9]{2})\.[0-9] ]] && echo "${BASH_REMATCH[1]}, ${BASH_REMATCH[2]}" 1, 14 不过 \s 的话还是要 [:blank:] 再也不用 grep -Po 捕捉多个组了!
Posted Sep 4
彻底解决了!我其实想做的只是“在 xfrm error 增加的时候记录此时的 skb 和 xfrm 状态”,但是这件事比我想象中的复杂太多太多了。 一开始我是在 kfree_skbmem 的地方检查 skb->net,因为 xfrm_stat 就在 net 里。但是发现读出来都是 0。 然后我发现这是 percpu_ptr,幸好 bpf 有几个 percpu helper,但是发现他们只能用于全局 ksym 的那种 percpu ptr,中道崩殂。 然后我检查了一下 percpu 的实现,原来就是 %gs 嘛,这有何难,我在之前 bpf for go 里抠 goid 就是从 %fs 里取出来的,照抄一番稍作修改不就行了。但是发现 thread->gsbase 都是 0,原来那个字段根本不用来存储 %gs,和 %fs 不一样。其实仔细想想也是,为啥 percpu 的数据会绑死在线程数据结构。 然后我开始“模糊化”,尝试用 pwru --output-only-if-hit kfree_skbmem 结合 pcap filter esp or (tcp and dst port 8000) 来过滤两个方向的流量,但是发现会漏掉不少 xfrm_stat 变化;而一旦放宽 pcap filter 又会匹配过多的流量导致数据丢失。这条路我一度觉得可以走通,都开始开香槟了,最后在 eks 上测试时被打击坏了。 做了好几个噩梦之后还是没有放弃,决定试试力量大的粗暴方案:kprobe attach address! 想想我在 bpf for go 是怎么绕过 kretprobe 的:搜索 ret 指令,k attach all those addresses。好,那我现在也 全量搜索 /proc/kcore 搜寻符合模式的指令,一共只有 500 多个,全部 kprobe attach 并不过分,在结合一些巧妙的过滤足以准确确定 “这就是 XFRM_INC_STATS” 。连夜糊出代码,在 eks 上运行,结果非常理想,既不错杀也不放过。 又一次实践了 “零知识 debug” 。 这个概念我在北京和奥格黄老师吃饭时说过一次。我说,我希望的 debugging tool 能让人在尽量少地拥有前置知识的情况下也依然可以通过观测到的异常现象来让大家推敲出这里有问题。与其相反的 debug 方式,也就是大家常用的 “富知识 debug”、“经验派 debug”,其实本质和瞎猜没有太大区别,都是通过搜索记忆中曾经遇到过的问题,来试试“这是不是以前遇到的那个问题的变种呢”。如果症状见得多,一下匹配准确了,猜对了,大家感叹“真是老中医,有经验”。这固然好,但是我想面向的是从无到有的,对程序员的前置要求也更低的,回合式战旗游戏般的分析。当然这都是很主观很理想的想法,每个人性格也有不同的解决问题方式,适合自己就好,就当我胡说八道。 还是说回这个 xfrm tracing,我彻底放弃了理解内核 policy + SA 并输出不同错误码的实现细节,转而观测 “出错时的 skb + policy + SA”,和 “期望状态” 一对比就能分析出问题,这完全不需要理解 XfrmInStateMismatch 和 XfrmInStateInvalid 和 XfrmInNoStates 有什么语义区别,我认为对调试 xfrm 报错来说也是降低了门槛,大家不同对着错误码统计数据猜测控制平面行为。
Posted Sep 3
今天晨间剧是“原来这就是 CO-RE” ,之前没有需求所以但丁问我的时候一问三不知。 总之大家在写 bpf 的时候用使用内核结构体。比如我有个 macro #define OFF_XFRM_MIB offsetof(struct net, mib) 但是在 5.x 和 6.x 内核下这个 offset 是不同的。 bcc / bpftrace 的解决办法是现场编译,但是这样需要在目标机器上安装 clang,这让我这种静态链接爱好者感到伤心。 另一个解法就是 CO-RE 了。总之你在 vmlinux.h 里把 struct net 的地方加上 __attribute__((preserve_access_index)) ,bpf loader 就能自动调节 bpf 字节码。(或者用 CORE_READ 系列 macro) 不要和 verifier 的字段调整混淆了。verifier 会调整字段,比如 tc-bpf 的 skb 参数,会把 skb->data_end 调整到 cb[5] ,但是 CO-RE relocation 是用户态的调整。首先在发布环境,clang 会编译出 bpf object,然后 go 把 bpf 字节码一起编译进 ELF;然后在运行环境,进程会在内存里通过运行时内核 btf 来调整 bpf opcode,然后再加载到内核。所以一个是用户态调整,一个是内核态调整。 其实概念不难,基本是工程问题。同时也感慨内核暴露的 debug info 真是多,我以前总以为要先下载 dbgsym,现在还下载个屁,直接 kallsyms + btf 就等于符号表 + 函数入口的 .debug_info ,还保证有 frame pointer,调试用户态 ELF 能有这种条件保证做梦都要笑醒。
Posted Aug 31
快要被 xfrm 折磨死了,也没啥心情好好阐述,总之 linux xfrm 有两个东西 policy 和 state,它有一套比 iptables 还复杂且没文档的规则去匹配 skb。你以为是先匹配一下 policy,如果找不到就扔掉,找得到再去找 state,错了,它甚至在多个网络分层里按照特别的顺序检查匹配,匹配使用的 key 根本没有文档记录且有一套只用于 xfrm 的术语,ingress egress 检查的东西不一样且一个东西在两个方向上有两个语义,拦截下来一个 skb 可能会产生 28 种错误码,内核只告诉你 28 种错误码的统计,而且错误的语义与其内核实现紧耦,文档不误导就不错了。举例来说,XfrmInNoStates 的文档只有一句话 Either inbound SPI, address, or IPsec protocol at SA is wrong,然而实际上也可能是 mark 不匹配。 且没有 bpf hook 点,且是 percpu_ptr,且没有 monitor API,且要在客户云环境上捉虫,且横跨五个版本,热补丁都打不过来。 这个傻逼 xfrm 已经把我组前 TL 逼得压力过大辞去了 TL 的帽子,从其他组租借了两位工程师并开始让其他 TL 一起协助,然而一个季度过去了依然没解决客户的问题,相信所有人心中都充满了感恩。感恩的心,感谢有你,伴我一生,让我有勇气做我自己。 算了,打一会儿游戏,反正解决不了问题迟早被开除。
Posted Aug 30
突然发现要正确 “用 Go 写一个命令行工具,执行两个进程,并把子进程的输出按照行缓冲收集起来统一打印到 Go 进程的标准输出” 并没有想象中那么容易,有不少容易犯错的地方。 问了 ChatGPT3.5,仔细提醒了它好几轮还是可以写出正确的代码,但是对于一位缺少相关知识的程序员来说很难看出 GPT 代码的问题。 而且程序员自己的代码习惯也影响出错的可能,比如用一个 outputCh 传来传去统一搜集输出,相比两个子进程分别返回两个 outputCh,前者的实现更不容易出错。而我一开始用后者的方式实现,果然全是 bug 🤡
Posted Aug 25
大家能看出这个一行修改 PR 有什么问题吗?我司两位工程师同意了这个 PR,然后由于没有测试,在 main 里投毒了半年才被发现,把我另一位同事气死,在群里问 daocloud ( 这个 PR 的作者的邮箱是 daocloud.io )有过任何有意义的贡献吗,没有的话以后直接拒绝。 我其实也有相似的经历:看似简单得不得了的一两行修改,就不用测了吧,结果一合并就投毒。人脑的推演就是如此不可靠,当然这也和我智力有关,所以多 trace,trace 不来加 printf 也行。