@@ -87,7 +87,7 @@ cd nettrace
8787make all
8888` ` `
8989
90- ** 注意** :对于不支持BTF的内核(内核版本低于5.3),在编译的时候需要加参数` COMPAT=1` ,如下所示:
90+ ** 注意** :对于不支持BTF的内核(内核版本低于5.3),在编译的时候需要加参数` COMPAT=1` ,采用兼容模式进行编译, 如下所示:
9191
9292` ` ` shell
9393make COMPAT=1 all
@@ -99,6 +99,8 @@ make COMPAT=1 all
9999make KERNEL=/home/ubuntu/kernel COMPAT=1 all
100100` ` `
101101
102+ ** 注意:** 兼容模式编译出来的nettrace工具只能运行在和` KERNEL` 内核版本相同的环境上。如果没有指定` KERNEL` ,那采用的就是当前编译环境上的内核头文件,这就要求编译环境和运行环境所使用的内核要完全相同才能正常运行。否则,会发生意想不到的意外。
103+
102104对于发行版版本较低,难以安装高版本clang的情况下,可以基于docker来进行代码的编译,具体可参考[2.4](# 2.4-基于docker编译)章节来进行安装。
103105
104106同时,对于` ubuntu 16.04/ubuntu 18.04` 系统,其内核似乎存在BUG,即其使用的内核版本实际为4.15.18,uname看到的却是4.15.0。这导致了加载eBPF程序的时候内核版本不一致,无法加载。因此对于这种情况,可以使用KERN_VER参数来手动指定内核版本(计算方式为:` (4<< 16) + (15<<8) + 18` ):
@@ -125,6 +127,8 @@ docker run -it --rm --network=host --privileged -v <nettrace path>:/root/nettrac
125127docker run -it --rm --network=host --privileged -v <nettrace path>:/root/nettrace -v /lib/modules/:/lib/modules/ -v /usr/src/:/usr/src/ imagedong/nettrace-build make -C /root/nettrace/ COMPAT=1 all
126128` ` `
127129
130+ ** 注意:** 兼容模式编译出来的nettrace工具只能运行在和` KERNEL` 内核版本相同的环境上。如果没有指定` KERNEL` ,那采用的就是当前编译环境上的内核头文件,这就要求编译环境和运行环境所使用的内核要完全相同才能正常运行。否则,会发生意想不到的意外。
131+
128132** 注意:** docker镜像可能会更新,为了使用最新的镜像,建议先试用命令` docker pull imagedong/nettrace-build` 来获取最新的容器镜像。
129133
130134# # 三、使用方法
@@ -160,6 +164,7 @@ Usage:
160164 --monitor enable 'monitor' mode
161165 --drop-stack print the kernel function call stack of kfree_skb
162166 --min-latency the minial time to live of the skb
167+ --trace-stack print call stack for traces or group
163168
164169 -v show log information
165170 --debug show debug information
@@ -183,8 +188,9 @@ Usage:
183188- ` monitor` :启用监控模式。一种轻量化的实时监控系统中网络异常的模式(对内核版本有一定要求)。
184189- ` hooks` :结合netfilter做的适配,详见下文
185190- ` drop` :进行系统丢包监控,取代原先的` droptrace`
186- - ` drop-stack` : 打印kfree_skb内核函数的调用堆栈
191+ - ` drop-stack` : 打印kfree_skb内核函数的调用堆栈,等价于 ` --trace-stack kfree_skb `
187192- ` min-latency` :根据报文的寿命进行过滤,仅打印处理时长超过该值的报文,单位为ms。该参数仅在默认和` diag` 模式下可用。
193+ - ` trace-stack` :指定需要进行堆栈打印的内核函数,可以指定多个,用“,”分隔。出于性能考虑,启用堆栈打印的内核函数不能超过16个。
188194
189195下面我们首先来看一下默认模式下的工具使用方法。
190196
@@ -347,6 +353,76 @@ begin trace...
347353[66.740110] [consume_skb ] ICMP: 192.168.122.8 -> 192.168.122.1 ping reply, seq: 1, id: 32535
348354` ` `
349355
356+ # ### 3.1.6 堆栈打印
357+
358+ 可以通过` --trace-stack` 来指定需要进行内核堆栈打印的` traces` ,使用方式与` --trace` 完全一致。出于性能的考虑,目前启用堆栈打印的内核函数不能超过16个。基本用法:
359+
360+ ` ` ` shell
361+ $ sudo ./nettrace -p icmp --trace-stack consume_skb,icmp_rcv
362+ begin trace...
363+ ***************** ffff88882cafd200,ffff88882cafdc00 ***************
364+ [2846531.810609] [nf_hook_slow ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956 *ipv4 in chain: OUTPUT*
365+ [2846531.810612] [ip_output ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
366+ [2846531.810613] [nf_hook_slow ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956 *ipv4 in chain: POST_ROUTING*
367+ [2846531.810615] [ip_finish_output ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
368+ [2846531.810617] [ip_finish_output2 ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
369+ [2846531.810619] [__dev_queue_xmit ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
370+ [2846531.810621] [dev_hard_start_xmit ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956 *skb is successfully sent to the NIC driver*
371+ [2846531.810623] [enqueue_to_backlog ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
372+ [2846531.810630] [__netif_receive_skb_core.constprop.0] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
373+ [2846531.810632] [ip_rcv ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
374+ [2846531.810634] [ip_rcv_core ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
375+ [2846531.810635] [nf_hook_slow ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956 *ipv4 in chain: PRE_ROUTING*
376+ [2846531.810637] [ip_local_deliver ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
377+ [2846531.810639] [nf_hook_slow ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956 *ipv4 in chain: INPUT*
378+ [2846531.810640] [nft_do_chain ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956 *iptables table:filter, chain:INPUT*
379+ [2846531.810642] [ip_local_deliver_finish] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
380+ [2846531.810644] [skb_clone ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
381+ [2846531.810649] [icmp_rcv ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
382+ Call Stack:
383+ -> icmp_rcv+0x1
384+ -> ip_local_deliver_finish+0x7f
385+ -> ip_local_deliver+0xea
386+ -> ip_rcv+0x16d
387+ -> __netif_receive_skb_one_core+0x89
388+ -> process_backlog+0xa9
389+ -> __napi_poll+0x2e
390+ -> net_rx_action+0x28f
391+ -> __do_softirq+0xfb
392+ -> do_softirq+0xa7
393+ -> __local_bh_enable_ip+0x79
394+ -> ip_finish_output2+0x170
395+ -> __ip_finish_output+0xae
396+ -> ip_finish_output+0x36
397+ -> ip_output+0x73
398+ -> ip_push_pending_frames+0xab
399+ -> raw_sendmsg+0x651
400+ -> inet_sendmsg+0x6e
401+ -> sock_sendmsg+0x60
402+ -> __sys_sendto+0x10a
403+ -> __x64_sys_sendto+0x24
404+ -> do_syscall_64+0x3f
405+ -> entry_SYSCALL_64_after_hwframe+0x72
406+
407+ [2846531.810651] [ping_rcv ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
408+ [2846531.810653] [ping_lookup.isra.0 ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
409+ [2846531.810654] [kfree_skb ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
410+ [2846531.810659] [consume_skb ] ICMP: 127.0.0.1 -> 127.0.0.1 ping reply, seq: 3, id: 51956
411+ Call Stack:
412+ -> consume_skb+0xb8
413+ -> consume_skb+0xb8
414+ -> skb_free_datagram+0x11
415+ -> raw_recvmsg+0xb2
416+ -> inet_recvmsg+0x11d
417+ -> sock_recvmsg+0x6e
418+ -> ____sys_recvmsg+0x90
419+ -> ___sys_recvmsg+0x7c
420+ -> __sys_recvmsg+0x60
421+ -> __x64_sys_recvmsg+0x1d
422+ -> do_syscall_64+0x3f
423+ -> entry_SYSCALL_64_after_hwframe+0x72
424+ ` ` `
425+
350426# ## 3.2 诊断模式
351427
352428使用方式与上面的一致,加个` diag` 参数即可使用诊断模式。上文的生命周期模式对于使用者的要求比较高,需要了解内核协议栈各个函数的用法、返回值的意义等,易用性较差。诊断模式是在生命周期模式的基础上,提供了更加丰富的信息,使得没有网络开发经验的人也可进行复杂网络问题的定位和分析。
0 commit comments