和追踪内核网络模块实战

核心提示今天给技术伙伴们分享一下 BCC 和 Ftrace 的使用方法,在开发实践过程中会遇到哪些问题,本篇文章都将一一道来~BCC 一个用于跟踪内核和操作程序的工具集,其软件包中包含了一些有用的工具和例子,是 eBPF 技术的一个前端,集成了 e

今天我就和技术伙伴们分享一下BCC和Ftrace的用法,以及在开发实践中会遇到哪些问题。这篇文章就一起来~

BCC是跟踪内核和操作程序的工具集。它的软件包包含了一些有用的工具和例子,是eBPF技术的前端。它集成了ebpf/kprobe/uprobe等工具,可以用Python封装,集成了一些常用的功能。

EBPF是近年来的热门技术。它的前身是BPF,即tcpdump用来过滤数据包的技术。EBPF扩展了BPF,它可以在内核中运行自定义程序,而无需修改内核源代码或加载内核模块。

Ftrace有两个概念,一个是广义的Ftrace框架,一个是狭义的跟踪技术。广义Ftrace框架包含了krpobe trace事件的多种跟踪技术,狭义Ftrace是本期的重点内容。今天,我们将重点介绍其中一种的用法。

Tracer的概念字面翻译为tracker,可以直观的理解为内核提供的一些追踪技术,如函数追踪、函数图追踪等。今天我们就重点介绍一下函数图追踪器,因为函数追踪器的很多功能都可以用BCC来实现,但是函数图是BCC不具备的功能。

功能图跟踪器的效果如下:

密件抄送效果如图所示:

如何使用BCC Ftrace?

> > > >安装

BCC可以用yum install bcc -y y安装,Ftrace不需要安装,由内核提供,打开CONFIG_DYNAMIC_FTRACE即可,默认开启该选项。

内核越高,BCC和Ftrace可以使用的函数就越多。也就是说,在低内核版本上,有些功能可能没有集成所以你不能使用这个功能。

密件抄送安装完成后,如图所示:

Ftrace需要手动打开一些内核选项:

跟踪语法:

Or name p:name:钉住内核函数名。

R::name:跟踪内核函数名的返回值。

Lib:name或p:Lib:name:在用户模式lib库中标记函数名。

R:lib:name:在用户模式lib库中跟踪函数名。

Path::name:跟踪位于path path下的用户状态函数名。

R:path:name:追溯位于path path下的用户状态函数名的返回值。

t:系统:名称:标桩名为系统:名称的跟踪点。

U:lib:name:在lib库中添加名为name的USDT探测器。

*:用于匹配任何字符的通配符。r选项允许使用正则表达式。

请参阅详细的“bpf之巅——深入了解linux系统和应用程序性能”

开发过程中的实际案例

> > > >安装

您可以看到环境中的同一个网段中有两个ip地址。这个环境将消息发送到作为客户端的服务器,服务器的地址是100.1.1.21。

> > > > ifdown测试

客户端和服务器正常通信时网卡通过ifdown宕机会发生什么?

我们可以看到,网卡宕机后客户端的返回值仍然正常,但是服务器在读取时被阻塞,所以无法再接收数据。

> > > > > ip链路设置测试

在客户端和服务器的正常通信中,通过ip link set ens192 down掉线会发生什么情况?

如你所见,客户端和服务器都可以正常发送和接收!

这里有两个问题:

为什么在ifdown后客户端仍然可以发送成功?

为什么在ifdown之后服务器接收不到消息,但是在ip link set down测试中服务器可以接收到消息?

接下来,我们将通过BCC和Ftrace跟踪工具来回答这两个问题。

Bctcrace trace _ _ sk _ dst _ check

根据调查和定位,我们确定了路线。路由是在ip层完成的,所以让我们看看ip层代码:

Ip _ queue _ xmit-> IP _ queue _ xmit IP _ queue _ xmit是IP层的入口函数。

如你所见,ip层的第一步是检查,所以我们需要看看检查的结果是什么,两个测试的区别是什么?

我们需要用BCC自带的Trace工具检查sk_dst_check的返回值。

> > > > > ip链路设置测试

> > > > ifdown

可以看到,在ifdown测试中,后面所有的返回值都变成NULL,而在ip link set down测试中,只有一个返回值变成NULL,然后又恢复正常。

经过了解,变成NULL的原因很简单。因为上一次成功的路由缓存在struct sock中,这个sk_dst_check检查路由缓存是否还可用,所以ifdown和ip link set down肯定是不可用的。

梳理代码逻辑后可以观察到,如果路由缓存不可用,则通过IP _ route _ output _ ports-> IP _ route _ output _ flow搜索路由表,搜索成功后会再次缓存。所以这里发生的是ifdown路由缓存失效后,路由表找不到有效路由。在ip链路建立之后,你可以通过查找路由表找到一条有效的路由。

所以我们通过Ftrace来看一下。两个测试中ip_route_output_flow的逻辑有什么区别?

跟踪ip_route_output_flow

Ip链接设置后的路由查找过程:

在ifdown之后,路由查找的过程:

对比两个输出和内核代码的区别,可以发现ifdown之后,设备会直接查找失败,然后直接返回上层——EHOSTUNREAD。并且在ip链路断开后,设备会被成功找到,然后路由会被成功找到。

对比内核代码中的查找路由过程,发现在fib_table_lookup中,有如下逻辑:

然后找到选项/proc/sys/net/IP v4/conf/ens 40/ignore _ routes _ with _ link down,该选项控制link down后原路由是否仍然生效,该值默认为0,即不忽略原路由项。

至此,我们终于可以回答前面的两个问题了:

为什么在ifdown后客户端仍然可以发送成功?

因为ip层将eOstunreach返回给tcp,而tcp重试,再次接收eOstunreach,然后重试/proc/sys/net/IP v4/tcp _ retries 2这么多次,TCP不会返回失败。

为什么在ifdown之后服务器接收不到消息,但是在ip link set down测试中服务器可以接收到消息?

因为ifdown之后设备被删除,EHOSTUNREACH直接返回tcp层,下一次重试会失败。于是消息发布了,sever收不到。

但是ip链路设置下来后,设备并没有被删除,默认情况下/proc/sys/net/IP v4/conf/ens 40/ignore _ routes _ with _ link down为0,即没有忽略已经宕机且链路已经掉线的路由,所以路由会被成功找到,然后发送成功,服务器会成功接收。

脚本

通过本期文章的分享,大家应该对BCC和Ftrace的用法有了一定的了解。后续会分享更多技术文章,可以继续关注。

 
友情链接
鄂ICP备19019357号-22