内容简介:tcp丢包分析系列文章代码来自谢宝友老师,由西邮陈莉君教授研一学生进行解析,本文由戴君毅整理,梁金荣编辑,贺东升校对。继续顺下实验代码,前面说过,我们需要为我们(在proc文件系统中)加入的条目编写操作集接口:实验的运行逻辑重点落在了write操作的实现中:
tcp丢包分析系列文章代码来自谢宝友老师,由西邮陈莉君教授研一学生进行解析,本文由戴君毅整理,梁金荣编辑,贺东升校对。
上次我们分析了 《“tcp丢包分析”实验解析(一)--proc文件系统》
继续顺下实验代码,前面说过,我们需要为我们(在proc文件系统中)加入的条目编写操作集接口:
实验的运行逻辑重点落在了write操作的实现中:
它的逻辑很简单,我们把用户写入的字符串通过 copy_from_user
传入到内核 buf
中,然后调用 sscanf
格式化 buf
为 cmd
,然后跟“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
中的内容。
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_kprobe
和 hook_tracepoint
, hook_kprobe
代码如下:
由于是动态追踪,需要先调用 kallsyms_lookup_name
检查是否有这个函数。如果有这个函数,那么就把kprobe的 pre_handler
和 post_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_TRACE
、 DEFINE_TRACE
这两个宏。可以阅读内核文档查阅一些高级的用法。
值得一提的是,实验代码为tracepoint设置了条件宏以便适应不同的内核版本,比较有意思,这里给出结构大家感受一下:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- “tcp丢包分析”实验解析(一)--proc文件系统
- “tcp丢包分析”实验解析(三)--驱动接收包过程
- 内网渗透实验:基于Cobaltstrike的一系列实验
- nfs 共享实验
- Arduino呼吸灯实验
- Ansible简介与实验
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
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》 这本书的介绍吧!