“tcp丢包分析”实验解析(二)--kprobe和tracepoint

栏目: IT技术 · 发布时间: 4年前

内容简介:tcp丢包分析系列文章代码来自谢宝友老师,由西邮陈莉君教授研一学生进行解析,本文由戴君毅整理,梁金荣编辑,贺东升校对。继续顺下实验代码,前面说过,我们需要为我们(在proc文件系统中)加入的条目编写操作集接口:实验的运行逻辑重点落在了write操作的实现中:

tcp丢包分析系列文章代码来自谢宝友老师,由西邮陈莉君教授研一学生进行解析,本文由戴君毅整理,梁金荣编辑,贺东升校对。

上次我们分析了 《“tcp丢包分析”实验解析(一)--proc文件系统》

继续顺下实验代码,前面说过,我们需要为我们(在proc文件系统中)加入的条目编写操作集接口:

实验的运行逻辑重点落在了write操作的实现中:

它的逻辑很简单,我们把用户写入的字符串通过 copy_from_user 传入到内核 buf 中,然后调用 sscanf 格式化 bufcmd ,然后跟“activate”和“deactiavate”比较,换句话说,如果用户输入“activate”,那么就可以开启丢包检测了。在加载模块后,用如下命令可以查看proc内容,由 drop_packet_show 实现:

cat /proc/mooc/net/drop-packet

结果如下:(省略了settings:)

activated:N

执行如下命令,可以激活丢包检测功能:

echo activate > /proc/mooc/net/drop-packet

再次查看proc文件内容,结果如下:

activated:y

那么接下来自然要看下 activate_drop_packet 干了些什么事:

可以看到,这段代码在 net_dev_xmit 中挂接一个 tracepoint 钩子,在 dev_queue_xmit / eth_type_trans / napi_gro_receive / __netif_receive_skb_core / tcp_v4_rcv 等函数的入口处挂接一个kprobe钩子。

那么到底什么是tracepoint?kprobe又是什么?说它们之前不得不说一下ftrace。ftrace(function trace)是利用gcc 编译器在编译时在每个函数的入口地址放置一个 probe 点,这个 probe 点会调用一个 probe 函数,这样这个probe 函数会对每个执行的内核函数进行跟踪并打印日志到 ring buffer 中,而用户可以通过 debugfs 来访问 ring buffer 中的内容。

“tcp丢包分析”实验解析(二)--kprobe和tracepoint

kprobe 是很早前就存在于内核中的一种动态 trace 工具。kprobe 本身利用了 int 3(在 x86 中)实现了 probe 点(对应图中的A)。使用 kprobe 需要用户自己实现 kernel module 来注册 probe 函数。kprobe 并没有统一的B、C 和 D。使用起来用户需要自己实现很多东西,不是很灵活。而在 functiontrace 出现后,kprobe 借用了它的一部分设计模式,实现了统一的 probe 函数(对应于图中的 B),并利用了 functiontrace 的环形缓存和用户接口部分,也就是 C 和 D 部分功能。

而tracepoint是静态的trace,说白了它就是内核开发人员提前设置好的跟踪点,也提供了管理桩函数的接口,它们已经编译进了内核,这样做既有优点也有缺点。优点是使用tracepoint的开销较小,并且它的API相对稳定;缺点也很明显,第一,默认的点明显不够多,可能覆盖不到你的需求;第二,你加一个点就需要重新编译内核,而kprobe不需要;第三,由于是静态的,不使用它也会造成开销(从内核文档可以看出这个问题已经被优化,现在基本忽略)。

实验代码中,挂接kprobe和tracepoint钩子的方法分别为 hook_kprobehook_tracepointhook_kprobe 代码如下:

由于是动态追踪,需要先调用 kallsyms_lookup_name 检查是否有这个函数。如果有这个函数,那么就把kprobe的 pre_handlerpost_handler 赋值给他,这两个都是钩子,会在其他地方定义好,它才是真正要干的事情,这是kprobe机制规定的,不用觉得奇怪。最后调用 register_kprobe 注册这个kprobe。

register_kprobe 函数非常复杂,我这里截取最为核心的部分:

prepare_kprobe 保存当前的指令, arm_kprobe 将当前指令替换为int3。然后就会执行 kprobe_int3_handler ,此时如果你的handler实现了并且注册了,那么就会执行你的handler了,这里应该就是“插桩”的本质了。

在设置单步调试 setup_singlestep 时,还会把 post_handler 的地址设置为下一个执行指令,以便 pre_handler 返回时可以“reenter”到kprobe异常,顺利执行 post_handler ,最后才执行原本执行的代码,它存放在kprobe结构体中。虽然这个实验并没有实现 post_handler ,但机制就是这样的。

Tracepoint相对简单一点,实验里直接调用了 tracepoint_probe_register ,就不展开说了,通常情况都是用 DECLARE_TRACEDEFINE_TRACE 这两个宏。可以阅读内核文档查阅一些高级的用法。

值得一提的是,实验代码为tracepoint设置了条件宏以便适应不同的内核版本,比较有意思,这里给出结构大家感受一下:

“tcp丢包分析”实验解析(二)--kprobe和tracepoint

“tcp丢包分析”实验解析(二)--kprobe和tracepoint


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Programming Rust

Programming Rust

Jim Blandy / O'Reilly Media / 2016-8-25 / GBP 47.99

This practical book introduces systems programmers to Rust, the new and cutting-edge language that’s still in the experimental/lab stage. You’ll learn how Rust offers the rare and valuable combination......一起来看看 《Programming Rust》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具