我想知道,Linux内核如何做一些事情(接收tcp数据包)。主要tcp函数以什么顺序被调用。我想同时查看中断处理程序(上半部分),下半部分,甚至在用户调用"read()"
之后由内核完成的工作。
如何从内核获取具有线性时间标度的函数跟踪?
我想从单个数据包中获取跟踪,而不是在接收第1000个数据包时获取内核的配置文件。
内核是2.6.18或2.6.23(在我的debian中受支持)。我可以添加一些补丁。
我认为至少可以实现您想要的目标的最接近的工具是内核ftrace。这是一个示例用法:
root@ansis-xeon:/sys/kernel/debug/tracing# cat available_tracers
blk function_graph mmiotrace function sched_switch nop
root@ansis-xeon:/sys/kernel/debug/tracing# echo 1 > ./tracing_on
root@ansis-xeon:/sys/kernel/debug/tracing# echo function_graph > ./current_trace
root@ansis-xeon:/sys/kernel/debug/tracing# cat trace
3) 0.379 us | __dequeue_entity();
3) 1.552 us | }
3) 0.300 us | hrtick_start_fair();
3) 2.803 us | }
3) 0.304 us | perf_event_task_sched_out();
3) 0.287 us | __phys_addr();
3) 0.382 us | native_load_sp0();
3) 0.290 us | native_load_tls();
------------------------------------------
3) <idle>-0 => ubuntuo-2079
------------------------------------------
3) 0.509 us | __math_state_restore();
3) | finish_task_switch() {
3) 0.337 us | perf_event_task_sched_in();
3) 0.971 us | }
3) ! 100015.0 us | }
3) | hrtimer_cancel() {
3) | hrtimer_try_to_cancel() {
3) | lock_hrtimer_base() {
3) 0.327 us | _spin_lock_irqsave();
3) 0.897 us | }
3) 0.305 us | _spin_unlock_irqrestore();
3) 2.185 us | }
3) 2.749 us | }
3) ! 100022.5 us | }
3) ! 100023.2 us | }
3) 0.704 us | fget_light();
3) 0.522 us | pipe_poll();
3) 0.342 us | fput();
3) 0.476 us | fget_light();
3) 0.467 us | pipe_poll();
3) 0.292 us | fput();
3) 0.394 us | fget_light();
3) | inotify_poll() {
3) | mutex_lock() {
3) 0.285 us | _cond_resched();
3) 1.134 us | }
3) 0.289 us | fsnotify_notify_queue_is_empty();
3) | mutex_unlock() {
3) 2.987 us | }
3) 0.292 us | fput();
3) 0.517 us | fget_light();
3) 0.415 us | pipe_poll();
3) 0.292 us | fput();
3) 0.504 us | fget_light();
3) | sock_poll() {
3) 0.480 us | unix_poll();
3) 4.224 us | }
3) 0.183 us | fput();
3) 0.341 us | fget_light();
3) | sock_poll() {
3) 0.274 us | unix_poll();
3) 0.731 us | }
3) 0.182 us | fput();
3) 0.269 us | fget_light();
这不是完美的,因为它不打印函数参数并且错过了一些静态函数,但是您可能不知道内核中谁在调用谁。
如果还不够,请使用GDB。但是,您可能已经知道,为内核调试设置GDB并不像对用户空间进程那样简单。如果需要,我更喜欢使用GDB + qemu。
追踪愉快!
更新:在以后的Linux发行版中,我建议使用trace-cmd
命令行工具,将其“包裹”在/sys/kernel/debug/tracing
周围。 trace-cmd
使用起来比原始接口内核提供的直观得多。
您想要oprofile。它可以为您提供整个系统(选定的子集)的时间,这意味着您可以跟踪从设备到应用程序的网络活动,并通过内核和所有库再次追溯。
我无法立即看到一次仅跟踪一个数据包的方法。特别是,可能很难获得这种细粒度的跟踪,因为中断处理程序的上半部分不应该进行任何阻塞(这很容易发生死锁)。
也许这过于花哨,但您是否看过源代码?我从经验中知道,在记录意图和引用RFC方面,TCP层都得到了很好的注释。
我强烈建议使用TCP / IP图解,特别是第2卷,实现(website)。它非常好,并且逐行遍历代码。在描述中,“将500个插图与15,000行真实有效的代码相结合...”。包含的源代码来自BSD内核,但是堆栈极其相似,因此将两者进行比较通常是有启发性的。
此问题很旧,可能与原始海报无关,但是我最近使用的一个不错的技巧对我很有帮助,那就是将sk_buf的“ mark”字段设置为某个值,如果该值匹配则仅设置“ printk” 。
因此,例如,如果您知道上半部分IRQ处理程序(如问题所提示的那样),则可以对某些检查进行硬编码(例如tcp端口,源IP,源MAC地址,好了,您就可以了)。标记为任意值(例如skb-> mark = 0x9999)。
然后一直到您仅在标记具有相同的值时才打印。只要没有其他人更改您的标记(就我所知,在典型设置中通常是这种情况),那么您只会看到您感兴趣的数据包。
由于大多数有趣的函数都得到了skb,所以它几乎可以处理所有可能有趣的事情。