掘金 后端 ( ) • 2024-05-08 17:41

文章转载至【字节跳动SYS Tech】公众号。原文链接点击:xcap:基于 eBPF 技术的下一代内核网络抓包工具 | 第二届eBPF开发者大会分享回顾

近日,第二届 eBPF 开发者大会于 4 月 13 日在陕西西安举行,本次大会上汇聚了 30+ 场精彩分享,来自高校、企业、开源社区的专家学者将分享他们在 eBPF 领域的研究成果、实践经验和成功案例,字节跳动 STE 团队的周锋受邀参加本次大会,与大家分享了《xcap:基于 eBPF 技术的下一代内核网络抓包工具》的主题演讲,本文整理了本次主题演讲的分享内容和视频,以供大家回顾查看。

简介

Linux 内核网络丢包是开发者经常遇到的问题场景,通常大家会借助 tcpdump 等传统网络抓包工具定位问题,但其效率较低,且在深度网络问题定位方面能力有限。随着 eBPF 技术的快速发展,出现了更高级的问题跟踪能力,借助这种能力,我们开发了下一代内核网络抓包工具:xcap。与传统网络工具只能作用于内核网络协议栈特定的点相比,xcap 可以几乎跟踪整个内核网络协议栈。我们用 tcpdump 语法作为过滤条件,以 skb(socket buffer)为上下文,可以轻松掌握整个报文在内核网络协议栈的完整踪迹,可以帮助开发者大大提高内核网络丢包问题的定位效率。另外 xcap 还可以抓取 AF_XDP 的包和 bypass 中内核协议栈的网络包(如 DPDK),能够覆盖多种网络场景。

传统工具的弊端

tcpdump

tcpdump 抓包点位置固定:入向是 xdp 之后,tc 之前;出向是 tc 之后。如果网络包通过其他方式进行路径优化后,不经过这几个位置,那么 tcpdump 就抓不到了,另外 tcpdump 还无法支持进程名,pid,namespace id 等其他过滤条件。

bpftrace+skboutput

bpftrace + skboutput 虽然支持了网络包的抓取和保存,但是它缺少了 tcpdump 语法的过滤功能。

xcap的优势

  • 自定义抓包位置:xcap 以 hook 函数来实现抓包,保证了抓包位置的灵活性,给使用者更大的自由度,可以覆盖更多的网络场景。
  • 功能可高度定制:xcap 基于 cbpfc 库,支持 tcpdump 过滤语法转成 c 代码,然后使用 bcc go 库可以实现即时编译,具备了 tcpdump 语法过滤包的功能。xcap 的 hook 是依赖 bpf 来实现的,我们可以通过丰富的 bpf helper 函数,获取很多的信息,诸如用栈的信息、进程名、pid、namespcace id 等等,基于这些信息,就可以高度定制多种功能。

另外 bpf 社区非常活跃,很多特性不断合入,也为 xcap 在高版本内核上的更多功能和更少 overhead 提供了助力。

xcap 通过 kprobe / tracepoint 方式实现函数的 hook,通过函数参数获取 skb 和 sock 关键结构体,拿到网络包的数据,通过 bpf map 和用户态进行数据传递。

image.png

典型使用场景

内核丢包

image.png

上述例子是用 iptables 下一条规则,eth1 上发出去 icmp 包全部丢掉。针对这样的场景,tcpdump 抓不到这个包,也很难分析其原因。而用 xcap 可以直接 hook kfree_skb_reason 函数,所有包的 skb 都会通过该函数进行释放内存,通过 tcpdump 过滤语法找到对应网络包的调用栈,然后找到丢包原因。

AF_XDP环境抓包

image.png

上述例子是 AF_XDP 的应用,使用 AF_XDP 进行发包,AF_XDP 网络包不会经过 tcpdump 抓包位置的流程,我们通过 xcap 和 tcpdump 同时抓包可以发现,tcpdump 没有抓到。

针对越来越丰富的网络场景,xcap 依靠其灵活的特性,可以覆盖更多的使用场景。

实现原理

整体架构图

xcap 主体框架依赖 cbpfc 库实现 tcpdump 语法转换成 c 函数,然后进行字符串替换,生成真正的 bpf 代码,然后再基于 go 版本 bcc 库,实现 bpf 代码即时编译。数据交互使用BPF_MAP_TYPE_PERF_EVENT_ARRAY将抓包的数据传递给用户态进程。

image.png

bpf侧框架

bpf 代码通过clang进行编译转成字节码,然后通过bpf syscall进行loadattach,在load阶段,内核bpf模块中的verifier会进行校验,检测 bpf 代码是否安全。

tcpdump语法到c函数的转换

实现逻辑比较清晰:解析 tcpdump 语法,然后转成对 skb 数据进行相应的偏移,最后读取数据进行比较。

以图中举例,tcp 过滤

struct ethhdr :14 个字节

struct iphdr.protocol:9 个字节

IPPROTO_TCP = 6,              /* Transmission Control Protocol        */

data+23 当地址解引用获取的值和 6 进行比较

image.png

skb结构体和报文的对应关系

sk_buff 结构体在网卡驱动层分配后,它的生命周期贯穿了整个内核协议栈,包含了网络包的所有数据,这也是我们抓包过程中需要获取到的最重要的参数之一,根据它的 head 结构体可以获取到网络包的内容,然后通过偏移量获取各个头部信息和 payload,存放到 map 中,然后进行 tcpdump 语法过滤。

image.png

利用sock伪造skb报文

考虑到抓包函数的不固定,所以就会碰到这样的情况:部分头部信息还没有走到解析流程,从而无法获取对应的偏移量和内容,这时候 xcap 会根据 sock 结构体中的其他成员来进行推导,然后 fake 头部信息放到 pcap buf 中。

image.png

pcap文件生成

bpf 根据 pcap 文件的格式,初始化 pcap 头部,然后将 ethhdr iphdr 和后续的数据进行填充,通过BPF_MAP_TYPE_PERF_EVENT_ARRAY进行数据的传递,用户态通过 epoll 系统调用进行事件监听和拷贝。

image.png

image.png

未来计划

为了进一步推进 eBPF 技术的发展,xcap 未来计划对外开源,并集成到火山引擎 veLinux 操作系统,与各位 Linux 系统、eBPF 开发者共享技术成果,通过开源的力量,与大家携手共同推进 eBPF 技术在国内的发展,同时欢迎大家关注后续开源进展。未来我们也将在以下几个方向进行优化,以达到更高的性能:

  • 使用 bpf ringbuf 代替 perf ringbuf,已达到更高的性能、更少的内存消耗;
  • 使用 vmlinux btf 来自动解析内核函数的参数
  • 使用 fentry,fexit 来降低 hook 的性能损耗
  • 尝试用低开销的 uprobe 技术,支持 DPDK 抓包(如:bpftime项目)

热门招聘

字节跳动STE团队诚邀您的加入!团队长期招聘,北京、上海、深圳、杭州、US、UK 均设岗位,点击 招聘详情 即可查看近期的最新招聘职位信息,有意向者可直接投递简历或咨询小助手微信:sys_tech,期待与你早日相遇,在字节共赴星辰大海!岗位多多,快来砸简历吧!