TGINSIGHT CHAT
Welcome to the Black Parade
@TheB1ackParade
MusicDeath has many faces, I look forward to seeing this one.
Recent posts
Page 9 of 76 · 907 posts
Posted Oct 17
我越来越觉得 bpf 射区对 percpu 的一些文档和用例是错误的,但我还不能确定,如果有老师能指出我的错误,我愿意 _ _ _ _ 🙏 如果稍微用 bpftrace <v0.41 用得多一点,可以看到这种报错 Looks like the BPF stack limit of 512 bytes is exceeded. Please move large on stack variables into BPF per-cpu array map. 这是由于 bpf 的 stack 限制是 512 bytes,如果要在栈上分配巨型 buff (结构体、字符串)就会报错。解决办法正如最后一句提醒所说,可以把巨型 buff 放到 per-cpu map 里,这是 bpf 社区里著名的最佳实践了,大概是这个意思: // sizeof(struct big) == 512, verifier decline! - struct big big = {}; // define a percpu_map whose entry value is of size 512, verifier pass! + struct big *big = bpf_map_lookup_elem(&percpu_map, &ZERO); 在 bpftrace 维护者 dxu 的博客里专门讲了这个问题,需要 ast 解析出全部的大字符串的总长度然后把字符串扔进 percpu map: https://dxuuu.xyz/big-strings.html 在 dylan 维护的 bpf doc 里,bpf 并发这一页也说 percpu map 是解决并发问题的好手段,简单直观,唯一的问题是 at cost of memory: https://docs.ebpf.io/linux/concepts/concurrency/ 在 cilium/cilium 里大量使用 percpu map 在 tailcall 之间传递数据,如这里 xdp meta: https://github.com/cilium/cilium/blob/v1.19.0-pre.1/bpf/include/bpf/ctx/xdp.h#L403 在 cilium/pwru 里我为了解决 __sync_fetch_and_add() 在 5.10 内核上无法运行的问题使用 percpu map 来模拟 sync_fetch_and_add(): https://github.com/cilium/pwru/blob/v1.0.10/bpf/kprobe_pwru.c#L414 在我很喜欢的工具 sockdump 里 (用来观测 unixsock stream) ,手动维护 percpu map 来临时存储 buff 再推给用户态: https://github.com/mechpen/sockdump/blob/d40ec77e960d021861220bc14a273c5dcad13160/sockdump.py#L40 在内核 bpf 子系统 tailcall 维护者 Leon 的 bpfsnoop 里也使用 percpu map 来临时存储 bpfsnoop_fgraph_tailcall_data: https://github.com/bpfsnoop/bpfsnoop/blob/v0.5.3/bpf/bpfsnoop_fgraph.c#L67 在 cilium latest doc (v1.18) 里说,bpf 程序运行时不会被内核抢占,所以请放心把 percpu 用做全局变量、规避 bpf stack 限制: https://docs.cilium.io/en/latest/reference-guides/bpf/toolchain/index.html However, there is a work-around in that the program can simply use a BPF map of type BPF_MAP_TYPE_PERCPU_ARRAY with just a single slot of arbitrary value size. This works, because during execution, BPF programs are guaranteed to never get preempted by the kernel and therefore can use the single map entry as a scratch buffer for temporary data, for example, to extend beyond the stack limitation. This also functions across tail calls, since it has the same guarantees with regards to preemption. 然而,我怀疑上面所有的资料里,只有一处是正确的,那就是 cilium/cilium 在 xdp 里使用 percpu 在 tailcall 之间传递数据,因为上面的场景里只有 native xdp / tc bpf 可以盖棺定论地说,软中断关闭,抢占调度禁止,可以安全使用 percpu map entry。 在其他的一般场景,比如 kprobe on unix_stream_sendmsg(), 由于 >v5.11 的内核正确地实现了 migrate_disable() [1],普通 bpf prog 只禁止了 cpu migration,但没有禁止 preempt[2],所以可能出现 prog1 运行到一半,已经在修改 percpu buffer 了,然后被抢占,在相同的 cpu 上运行 prog2,也修改 percpu buffer,最后切回 prog1 的时候 percpu buffer 已经被玩烂,救不回来了。 [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=74d862b682f51e45d25b95b1ecf212428a4967b0 [2] https://lwn.net/Articles/812503/ 我目前的改法是使用 ringbuf_reserve 来获取一个大 buffer,用起来感觉还可以,就是不灵活,size 必须是常数,我最爱的变长 msg ringbuf 从此就只能说再见了。。。 👋 因此我之前写的这条 post 千万不要读,基本是错的,完全没有考虑中断抢占的情况: https://t.me/c/1459082815/752 (更多惊喜见昨天的 lwn,想象一下 bpf_spin_lock 遇上 preempt 会发生什么😊: https://lwn.net/SubscriberLink/1039374/986a9adb75d63ae0/) 软件工程太勃大茎深了😋
Posted Oct 16
不是,怎么 Kraftwerk 中国演出被取消过后三天我才知道他们要来中国???啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊!!!!!
Posted Oct 14
第四个 sockmap bug,P0 级 😀 我已经不想知道为什么它有这么多 bug 了,苦难太多了,soul-like + action + rogue,我需要来一点回合制战旗 crpg 恢复一下神智,现在这玩法也太魂了,脑壳痛。
Posted Oct 14
又一个 sockmap bug,彻底麻了,个个都是 P0 级 bug,一挂就是一整个节点,放到大明王朝都被砍了九个头了,这就是 kernel 😀 合订本: 0. (by arthurchiao) sockmap tcp socket 建连后无法收包 https://arthurchiao.art/blog/tcp-requests-stuck-after-connection-established/ 1. sockmap 导致 splice 发包的 tcp socket 无法收包 https://github.com/jschwinger233/bpf_msg_redirect_bug_reproducer 2. sockmap 杀死 mptcp 进程 https://github.com/jschwinger233/bpf_sockmap_mptcp_bug_reproducer 3. sockmap 导致 read tcp socket 返回 EOF https://github.com/jschwinger233/sockmap_sk_skb_stream_eof_bug_reproducer 让我看看被开除前这个 bug 清单还能再添加几个惊喜 😀
Posted Oct 10
以防有人不知道,Ubuntu 25.10 'Questing Quokka' 是西澳 Perth(我的精神故乡 😀)的特产小动物 “短尾矮袋鼠” ,我最爱的小动物之一,希望大家都去 Perth 玩😊
Posted Oct 10
看到这个讨论[1],意识到有朋友可能还不知道:Python venv 会对所有安装到 venv 的 bin 目录的东西带上合适的 shebang,使得直接运行或软链接都能工作,不需要 activate venv。我觉得这样非常方便,已经很久没 activate 过任何 venv 了。 $ python3 -m venv path-to-venv $ path-to-venv/bin/pip install fava # 不用进入 venv,直接运行其中的 pip 就可以 $ ln -s path-to-venv/bin/fava ~/.local/bin/fava $ fava # 软链接也可以直接运行 [1]: https://news.ycombinator.com/item?id=45523767
Posted Oct 8
Bryan Adams 我也喜欢,大学时天天听着 《Here I Am》 跑步,2012 年还写过一篇 qq 空间日志以此为标题。。。 打住,再说下去老人味就要射出来了🤬
Posted Oct 8
我每次看 Yonghong Song 做事都会想起《文明6》里的“大工程师”: https://lwn.net/Articles/1016105/ 如果说“好工程师”的标准是解决问题的能力和想象力,那“大工程师”还需要加上 改善生态的能力 ,这不仅包括硬实力——精通 clang/gcc/bpf/elf,而且愿意一次次站上去,把一个很多人都遇到过的小问题拿到台面上讨论,建立社区共识,改善基建生态。说这个问题是小问题是因为很多人都遇到过,我自己都遇到过太多次了,最后无非是 llvm-objdump 看一下哪个变量被优化了然后加上 volatile 就心满意足了。好工程师止步于此,大工程师才刚刚开始。
Posted Oct 7
Spotify 终于支持无损了!(太落后了,苹果四年前就支持了。。。
Posted Oct 7
买了新的 Airpods...4😊 不要问我为什么不买 Pro3,因为看b站的翻车视频看得我害怕,加上我一直想要开放式关系的、非阻塞的、对我潮湿音道更健康的,半入耳式耳机。用了一天了感觉还可以,符合预期。
Posted Oct 6
re-review https://dlee-libo.github.io/2020/05/31/bpftrace-kernel-journey/🤬 这是五年前我人生第一次排查内核网络栈连通性问题,完全不会,请教最爱的同事波波,他用一个周末钻木取火纯肉眼反汇编 + kprobe 找到了问题写下了这篇荡气回肠的青词。这五年里我每次进步一点都要来回头看看这个最初的问题,正好昨天评论区又提到 rp filter,这就是一个 rp_filter=2 造成的 arp 丢包问题没有丢,压根就没回。 在 ubuntu desktop 2404 kernel 6.14.0-29 依然可以按照博客脚本直接复现,症状是 ping 不通,pwru/tcpdump/ip-neigh 一下发现 arp 没回应,开始检查 arp。 arp 和一般的连通性问题不同,arp 的问题可能根本不是丢包。比如这一题尝试用 pwru 检查 arp 请求和返回最多只能看到: $ pwru --filter-track-skb --output-caller 'arp and dst host 169.254.0.1' arp_rcv __netif_receive_skb_one_core arp_process arp_rcv ip_route_input_noref arp_process ip_route_input_slow ip_route_input_noref __mkroute_input ip_route_input_slow fib_validate_source __mkroute_input __fib_validate_source fib_validate_source ip_handle_martian_source __mkroute_input consume_skb arp_process 完全没有丢包,看起来就像是正确无误地处理了 arp skb 一样。 用 retsnoop 摸奖也毫无结果,下面的命令检查所有包含 arp 的内核函数的返回 errno: retsnoop -a '*arp*' -e '*arp*' -x any 完全没有任何 errno。 这时候只能根据 pwru 的 skb lifetime tracing 输出随缘读一下内核源代码,发现最可疑的似乎是 arp_process() 这个内核函数里的 if (...) // 一大堆嵌套 if,巨型 code block arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, sha, reply_dst); 没有执行。 我在 PyCon CN 25 说过,查“某事为何没有发生”比“某事为何发生”更难,后者找到发生怪事的 hook 一波 bt 带走,前者连 attach point 都不知道从哪里下手。 波巨魔在五年前直接肉翻汇编找到 offset 打 kprobe,但现在我们有了 bpfsnoop lbr,来试试看。 注意 arp_send_dst() 所在的巨型 code block 之后是一个 neigh_lookup if (...) { // 一大堆嵌套 if,巨型 code block arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, sha, reply_dst); } n = __neigh_lookup(&arp_tbl, &sip, dev, 0); 思路就来了,在 neigh_lookup 的入口检查 lbr 不就知道肛才运行的谜语代码是怎么运行了的吗 $ bpfsnoop -k neigh_lookup --output-lbr --filter-arg 'dev->ifindex == 9' -m entry --filter-pid $(pidof ping) ip_route_input_noref+0x6e (net/ipv4/route.c:2489) -> __rcu_read_unlock+0x0 (kernel/rcu/tree_plugin.h:431) arp_process+0x4a4 (net/ipv4/arp.c:839) -> arp_process+0x1a5 (include/net/neighbour.h:545) arp_process+0x1be (include/net/neighbour.h:545) -> neigh_lookup+0x0 (net/core/neighbour.c:579) 最后三行输出已经很清楚了,看一眼 net/ipv4/arp.c:839 的代码 if (arp->ar_op == htons(ARPOP_REQUEST) && ip_route_input_noref(skb, tip, sip, 0, dev) == 0) { 是 ip_route_input_noref(skb, tip, sip, 0, dev) == 0 这个条件失败了。 检查 ip_route_input_noref 的 retval 也很简单 $ sudo bpfsnoop -k ip_route_input_noref --output-arg retval --filter-pkt 'arp and dst host 169.254.0.1' ← retval=(enum skb_drop_reason)SKB_DROP_REASON_IP_RPFILTER 已经出现了 SKB_DROP_REASON_IP_RPFILTER,结束。最终原因是 rp_filter 是 max(netdev, all) 的 sysctl,在复现脚本里只修改了 netdev.rp_filter=0 不足够,还要再改 all.rp_filter=0。 非常感谢 Leon Hwang (tg ch: https://t.me/eBPFTalker) 的工具 bpfsnoop,我已经安利了五六次,自己也撸起袖子打算做点微小的贡献。 这些微小的星光推动计算机工程的边界,make a better world.
Posted Oct 5
我才发现 tracee (https://github.com/aquasecurity/tracee) logo 长得很像 dildo,照片拍摄于 2018 悉尼🌭