xcap:基于eBPF技术的下一代内核网络抓包工具
xcap:基于eBPF技术的下一代内核网络抓包工具
Linux内核网络丢包是开发者经常遇到的问题场景,通常大家会借助tcpdump等传统网络抓包工具定位问题,但其效率较低,且在深度网络问题定位方面能力有限。随着eBPF技术的快速发展,出现了更高级的问题跟踪能力,借助这种能力,我们开发了下一代内核网络抓包工具:xcap。
简介
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和用户态进行数据传递。
典型使用场景
内核丢包
上述例子是用iptables下一条规则,eth1上发出去icmp包全部丢掉。针对这样的场景,tcpdump抓不到这个包,也很难分析其原因。而用xcap可以直接hookkfree_skb_reason函数,所有包的skb都会通过该函数进行释放内存,通过tcpdump过滤语法找到对应网络包的调用栈,然后找到丢包原因。
AF_XDP环境抓包
上述例子是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将抓包的数据传递给用户态进程。
bpf侧框架
bpf代码通过clang进行编译转成字节码,然后通过bpf syscall进行load和attach,在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进行比较
skb结构体和报文的对应关系
sk_buff结构体在网卡驱动层分配后,它的生命周期贯穿了整个内核协议栈,包含了网络包的所有数据,这也是我们抓包过程中需要获取到的最重要的参数之一,根据它的head结构体可以获取到网络包的内容,然后通过偏移量获取各个头部信息和payload,存放到map中,然后进行tcpdump语法过滤。
利用sock伪造skb报文
考虑到抓包函数的不固定,所以就会碰到这样的情况:部分头部信息还没有走到解析流程,从而无法获取对应的偏移量和内容,这时候xcap会根据sock结构体中的其他成员来进行推导,然后fake头部信息放到pcap buf中。
pcap文件生成
bpf根据pcap文件的格式,初始化pcap头部,然后将ethhdr、iphdr和后续的数据进行填充,通过BPF_MAP_TYPE_PERF_EVENT_ARRAY进行数据的传递,用户态通过epoll系统调用进行事件监听和拷贝。
未来计划
为了进一步推进eBPF技术的发展,xcap未来计划对外开源,并集成到火山引擎veLinux操作系统,与各位Linux系统、eBPF开发者共享技术成果,通过开源的力量,与大家携手共同推进eBPF技术在国内的发展,同时欢迎大家关注后续开源进展。未来我们也将在以下几个方向进行优化,以达到更高的性能:
- 使用bpf ringbuf代替perf ringbuf,已达到更高的性能、更少的内存消耗;
- 使用vmlinux btf来自动解析内核函数的参数
- 使用fentry、fexit来降低hook的性能损耗
- 尝试用低开销的uprobe技术,支持DPDK抓包(如:bpftime项目)