文章目录
什么是bcc和ftrace
bcc是ebpf技术的一个前端,集成了ebpf/kprobe/uprobe的很多东西,对一些常见功能做了整合。而ebpf是近几年出现的比较热门的一项技术,它的前身是bpf(Berkeley Packet Filter),也就是我们tcpdump使用的过滤数据包的技术。ebpf对bpf进行了扩展,它能在内核中运行自定义程序, 而无需修改内核源码或者加载内核模块。
ftrace有两种概念,一种是广义的ftrace框架,一种是狭义的追踪技术。广义的ftrace框架包含了krpobe trace event很多追踪技术,而狭义的ftrace就是我们今天的重点,我们会对其中一种tracer的使用做着重介绍。
tracer的概念可以直译为追踪器,可以理解为内核提供的一些追踪技术,比如有function tracer,function graph tracer等等,我们今天着重介绍function graph tracer,因为function tracer的很多功能用bcc就可以实现,而function graph却是bcc没有的功能。
function graph tracer的效果如图
bcc 效果如图
怎样使用bcc ftrace
安装
bcc使用yum install bcc -y就能安装。ftrace不用安装,是内核提供的,只要开启了CONFIG_DYNAMIC_FTRACE
就行,而这个选项我们是默认开启的。
内核版本越高,bcc和ftrace能使用的功能就越多,也就是说,在低内核版本上,可能一些功能并没有集成进去也就不能使用。
bcc安装完成后如图所示
而ftrace需要手动开启内核一些选项
trace语法:
name或者p:name:对内核函数name()进行插桩
r::name: 对内核函数name()的返回值进行插桩
lib:name或者p:lib:name: 对用户态lib库中的函数name()进行插桩
r:lib:name:对用户态lib库中的函数name()进行插桩
path::name: 对位于path路径下的用户态函数name()进行插桩
r:path:name: 对位于path路径下的用户态函数name()的返回值进行插桩
t:system:name: 对名为system:name的跟踪点进行插桩
u:lib:name: 对lib库中名为name的USDT探针进行插桩
*: 用来匹配任意字符的通配符。-r选项允许使用正则表达式
详细可见《bpf之巅——洞悉linux系统和应用性能》
开发过程中的一个实际案例
环境
ifdown测试
我们可以看到,client在down掉网卡后,返回值还是正常的,但是server接受不到数据了
ip link set down 测试
这里有两个问题:
-
为什么ifdown之后,client还是可以发送成功?
-
为什么ifdown之后,server收不到消息,而ip link set down测试中server可以接收到消息
bcc trace 追踪__sk_dst_check()
ip link set down
ifdown
ftrace追踪ip_route_output_ports()
Ip link set down后,路由查找的过程
ifdown后,路由查找的过程
对比两种输出的不同和内核代码,可以发现,ifdown后,会直接查找设备失败,进而直接返回给上层(tcp)-EHOSTUNREAD。而ip link down后,会查找设备成功,进而查找路由成功。
再对比内核代码,发现在fib_table_lookup()
中,有以下逻辑:
然后发现/proc/sys/net/ipv4/conf/ens40/ignore_routes_with_linkdown
这个选项,控制了link down后,原来路由是否还会生效,而这个值默认是0,也就是不忽略原来的路由项。
https://blog.csdn.net/sinat_20184565/article/details/106182579
至此,终于真相大白,我们可以来解答我们的两个疑问了
-
为什么ifdown之后,client还是可以发送成功?
- 因为ip层向tcp返回了EHOSTUNREACH,而tcp进行了重试,再次收到EHOSTUNREACH,再达到重试
/proc/sys/net/ipv4/tcp_retries2
这么多次之前,tcp是不会返回失败的。
- 因为ip层向tcp返回了EHOSTUNREACH,而tcp进行了重试,再次收到EHOSTUNREACH,再达到重试
-
为什么ifdown之后,server收不到消息,而ip link set down测试中server可以接收到消息。
- 因为ifdown后,设备被删除了,直接向tcp层返回了EHOSTUNREACH,而下一次重试又会失败。所以消息发不出去,server收不到消息
- 而ip link set down后,设备没有被删除,而
/proc/sys/net/ipv4/conf/ens40/ignore_routes_with_linkdown
默认为0,也就是不忽略已经down掉的Link的路由,所以会查找路由成功,进而发送成功,server接收成功。
脚本
#!/bin/bash
if [ $# != 2 ]; then
echo "USAGE: $0 func_name command"
echo "e.g: $0 yrfs_ops_write \"echo aa > /mnt/yrfs/aa\""
exit -1
fi
num_args="$#"
cmd="${@: -1}"
func_name="$1"
echo $cmd
debugfs=/sys/kernel/debug
echo nop > $debugfs/tracing/current_tracer
echo 0 > $debugfs/tracing/tracing_on
# echo $$ > $debugfs/tracing/set_ftrace_pid
echo function_graph > $debugfs/tracing/current_tracer
echo $func_name > $debugfs/tracing/set_graph_function
# options
echo 1 > $debugfs/tracing/options/funcgraph-tail
echo 1 > $debugfs/tracing/options/funcgraph-proc
echo 1 > $debugfs/tracing/tracing_on
eval $cmd
cp $debugfs/tracing/trace ~/trace_ret
echo nop > $debugfs/tracing/current_tracer
echo 0 > $debugfs/tracing/tracing_on