如果我們想看看tcp發(fā)送數(shù)據(jù)的大小,我們需要獲取第三個(arg2)參數(shù)size的值。我們嘗試寫一個bpftrace的小腳本看一下size的值。
bpftrace是基于bpf實現(xiàn)的追蹤工具,之前的文章的分享過bpftool,bpftrace的功能更加強大。

在內(nèi)核中tcp發(fā)送數(shù)據(jù)是通過tcp_sendmsg 方法實現(xiàn)的
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
如果我們想看看tcp發(fā)送數(shù)據(jù)的大小,我們需要獲取第三個(arg2)參數(shù)size的值。我們嘗試寫一個bpftrace的小腳本看一下size的值。
執(zhí)行效果如下:
# bpftrace -e 'k:tcp_sendmsg { @size
Attaching 2 probes...
@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 | |
可以看到size的直方圖,可以看到類似正態(tài)分布。
如果你想看看都是哪些進程大量發(fā)送數(shù)據(jù),可以添加大于 1024 字節(jié)過濾器,如下:
# bpftrace -e 'k:tcp_sendmsg /arg2 > 1024/ { printf("PID %d,COMM: %s: %d bytes\n", pid,comm, arg2); }'
Attaching 1 probe...
PID 63700,COMM: kube-apiserver: 1581 bytes
PID 68206,COMM: etcd: 1079 bytes
PID 1784,COMM: kube-scheduler: 2249 bytes
PID 63700,COMM: kube-apiserver: 1581 bytes
PID 63700,COMM: kube-apiserver: 5811 bytes
PID 63700,COMM: kube-apiserver: 1581 byt
前面都是基于 tcp_sendmsg 的size參數(shù)去玩的,我們更進一步,看看發(fā)送數(shù)據(jù)包的內(nèi)容,也就tcp_sendmsg的第一個參數(shù)。我們寫這樣一段腳本
#!/usr/local/bin/bpftrace
#include <net/sock.h>
k:tcp_sendmsg
{
@sk[tid] = arg0;
@size[tid] = arg2;
}
kr:tcp_sendmsg
/@sk[tid]/
{
$sk = (struct sock *)@sk[tid];
$size = @size[tid];
$af = $sk->__sk_common.skc_family;
if ($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 bytes, retval %d\n",
$saddr, $lport, $daddr, $dport, $size, retval);
} else {
printf("IPv6...\n");
}
delete(@sk[tid]);
delete(@size[tid]);
}
這段腳本有點多,初學(xué)者可能有點懵,我稍微解釋一下,腳本有兩個掛載點,k代表kprobe,kr代表kretprobe。腳本通過解析 sk 這個結(jié)構(gòu)體,去獲取tcp 包源IP和端口、目的IP和端口,這里稍微需要了解一下內(nèi)核的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)體。retval 代表tcp_sendmsg 函數(shù)返回值,這個bpftrace原生支持的。
執(zhí)行這個腳本
127.0.0.1 2379 -> 127.0.0.1 1236 : 64 bytes, retval 64
127.0.0.1 1236 -> 127.0.0.1 2379 : 51 bytes, retval 51
127.0.0.1 2379 -> 127.0.0.1 1236 : 38 bytes, retval 38
10.133.18.121 65286 -> 10.133.18.121 6443 : 257 bytes, retval 257
是不是非常有意思,我們基于這些數(shù)據(jù)生成每個節(jié)點之間的網(wǎng)絡(luò)關(guān)系。