当前位置: 首页 > 科技观察

使用Bpftrace看穿Linux内核

时间:2023-03-22 12:43:35 科技观察

bpftrace是一个基于bpf的跟踪工具。上一篇分享了bpftool,bpftrace的功能更强大。在内核中,tcp通过tcp_sendmsg方法发送数据inttcp_sendmsg(structsock*sk,structmsghdr*msg,size_tsize);如果我们要查看tcp发送数据的大小,我们需要得到第三个(arg2)参数size的值。让我们尝试编写一个小的bpftrace脚本来查看size的值。执行效果如下:#bpftrace-e'k:tcp_sendmsg{@sizeAttaching2probes...@size:[1]6||[2,4)0||[4,8)0||[8,16)0||[16,32)110|@@@@@@@@|[32,64)687|@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|[64,128)429|@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|[128,256)60|@@@@|[256,512)96|@@@@@@|[512,1K)46|@@@|[1K,2K)28|@@|[2K,4K)8||[4K,8K)10||可以看到大小的直方图,类似正态分布。如果想查看哪些进程发送的数据量大,可以添加大于1024字节的过滤器,如下:#bpftrace-e'k:tcp_sendmsg/arg2>1024/{printf("PID%d,COMM:%s:%d字节\n",pid,comm,arg2);}'附加1个探测器...PID63700,COMM:kube-apiserver:1581bytesPID68206,COMM:etcd:1079bytesPID1784,COMM:kube-scheduler:2249bytesPID63700,COMM:kube-apiserver:1581bytesPID63700,COMM:kube-apiserver:5811bytesPID63700,COMM:kube-apiserver:5811bytesPID:kube-apiserver:1581byte基于tcp_sendmsg的size参数。我们再进一步看下发送数据包的内容,也就是tcp_sendmsg的第一个参数。我们写这样一个脚本#!/usr/local/bin/bpftrace#includek:tcp_sendmsg{@sk[tid]=arg0;@size[tid]=arg2;}kr:tcp_sendmsg/@sk[tid]/{$sk=(structsock*)@sk[tid];$size=@size[tid];$af=$sk->__sk_common.skc_family;如果($af==AF_INET){$daddr=ntop($af,$sk->__sk_common.skc_daddr);$saddr=ntop($af,$sk->__sk_common.skc_rcv_saddr);$lport=$sk->__sk_common.skc_num;$dport=$sk->__sk_common.skc_dport;$dport=($dport>>8)|(($dport<<8)&0xff00);printf("%-15s%-5d->%-15s%-5d:%d字节,retval%d\n",$saddr,$lport,$daddr,$dport,$size,retval);}else{printf("IPv6...\n");}删除(@sk[tid]);删除(@size[tid]);}这段脚本有点多,初学者可能有点懵,稍微解释一下,脚本有两个挂载点,k代表kprobe,kr代表kretprobe。脚本解析sk结构,获取tcp包的源IP和端口,目的IP和端口。这里我们需要了解一下内核的基本数据结构。retval表示tcp_sendmsg函数的返回值,bpftrace原生支持。执行这个脚本127.0.0.12379->127.0.0.11236:64bytes,Retval64127.0.0.11236->127.0.0.02379:51bytes,Retval51127.0.0.02379->127.0.0.11231.1.1S:381.1.1S:381.11381.11.1381.1.1381.11.1381.1381.381.381.1381.1381.381.1381.1381.138.138.138.138.138.138.381.38.38。18.12165286->10.133.18.1216443:257bytes,retval257是不是很有意思,我们根据这些数据生成各个节点之间的网络关系。