【问题标题】:Path of UDP packet in linux kernellinux内核中UDP数据包的路径
【发布时间】:2013-01-18 20:54:38
【问题描述】:

我想在 Linux 内核中查找 UDP 数据包的路径。为此,我想阅读一些文档(到目前为止,我有this,这是针对 TCP 的),然后在相关的内核函数中有一些 printk 语句来确认这一点。我将通过重新编译内核代码来做到这一点。

这是解决问题的方法吗?您有什么建议/参考吗?

【问题讨论】:

  • W.R. Stevens,TCP/IP Illustrated, 第二卷,对 BSD 内核进行了完整的说明,我怀疑它同样提供了丰富的信息,并且不需要内核干预。

标签: networking linux-kernel udp


【解决方案1】:

具体回答您的问题,要了解 IPv4 的 UDP 处理,您可以使用 ftrace,如下所示:

在入口(接收方):

 96882  2)               |                                ip_local_deliver_finish() {
 96883  2)   0.069 us    |                                  raw_local_deliver();
 96884  2)               |                                  udp_rcv() {
 96885  2)               |                                    __udp4_lib_rcv() {
 96886  2)   0.087 us    |                                      __udp4_lib_lookup();
 96887  2)               |                                      __skb_checksum_complete_head() {
 96888  2)               |                                        skb_checksum() {
 96889  2)               |                                          __skb_checksum() {
 96890  2)               |                                            csum_partial() {
 96891  2)   0.161 us    |                                              do_csum();
 96892  2)   0.536 us    |                                            }
 96893  2)               |                                            csum_partial() {
 96894  2)   0.167 us    |                                              do_csum();
 96895  2)   0.523 us    |                                            }
 96896  2)               |                                            csum_partial() {
 96897  2)   0.158 us    |                                              do_csum();
 96898  2)   0.513 us    |                                            }
 96899  2)               |                                            csum_partial() {
 96900  2)   0.154 us    |                                              do_csum();
 96901  2)   0.502 us    |                                            }
 96902  2)               |                                            csum_partial() {
 96903  2)   0.165 us    |                                              do_csum();
 96904  2)   0.516 us    |                                            }
 96905  2)               |                                            csum_partial() {
 96906  2)   0.138 us    |                                              do_csum();
 96907  2)   0.506 us    |                                            }
 96908  2)   5.462 us    |                                          }
 96909  2)   5.840 us    |                                        }
 96910  2)   6.204 us    |                                      }

跟踪的另一部分如下所示:

 98212  2)               |                              ip_rcv() {
 98213  2)               |                                ip_rcv_finish() {
 98214  2)   0.109 us    |                                  udp_v4_early_demux();
 98215  2)               |                                  ip_route_input_noref() {
 98216  2)               |                                    fib_table_lookup() {
 98217  2)   0.079 us    |                                      check_leaf.isra.8();
 98218  2)   0.492 us    |                                    }

对于网络代码的出口,下面提取了一些sn-ps:

 4)   0.547 us    |  udp_poll();
 4)               |  udp_sendmsg() {
 4)               |    udp_send_skb() {
 4)   0.387 us    |      udp_error [nf_conntrack]();
 4)   0.185 us    |      udp_pkt_to_tuple [nf_conntrack]();
 4)   0.160 us    |      udp_invert_tuple [nf_conntrack]();
 4)   0.151 us    |      udp_get_timeouts [nf_conntrack]();
 4)   0.145 us    |      udp_new [nf_conntrack]();
 4)   0.160 us    |      udp_get_timeouts [nf_conntrack]();
 4)   0.261 us    |      udp_packet [nf_conntrack]();
 4)   0.181 us    |      udp_invert_tuple [nf_conntrack]();
 4)   0.195 us    |      udp_invert_tuple [nf_conntrack]();
 4)   0.170 us    |      udp_invert_tuple [nf_conntrack]();
 4)   0.175 us    |      udp_invert_tuple [nf_conntrack]();
 4)               |      udp_rcv() {
 4) + 15.021 us   |        udp_queue_rcv_skb();
 4) + 18.829 us   |      }
 4) + 82.100 us   |    }
 4) + 92.415 us   |  }
 4)               |  udp_sendmsg() {
 4)               |    udp_send_skb() {
 4)   0.226 us    |      udp_error [nf_conntrack]();
 4)   0.150 us    |      udp_pkt_to_tuple [nf_conntrack]();
 4)   0.146 us    |      udp_get_timeouts [nf_conntrack]();
 4)   1.098 us    |      udp_packet [nf_conntrack]();
 4)               |      udp_rcv() {
 4)   1.314 us    |        udp_queue_rcv_skb();
 4)   3.282 us    |      }
 4) + 20.646 us   |    }

以上在ftrace中称为函数图:

How to make a linux kernel function available to ftrace function_graph tracer?

我的用于跟踪 udp 的 bashscript 如下(以 root 身份运行):

#!/bin/bash

mkdir /debug
mount -t debugfs nodev /debug
mount -t debugfs nodev /sys/kernel/debug
echo udp_* >/debug/tracing/set_ftrace_filter
echo function_graph >/debug/tracing/current_tracer
echo 1 >/debug/tracing/tracing_on
sleep 20
echo 0 >/debug/tracing/tracing_on
cat /debug/tracing/trace > /tmp/tracing.out$$

现在输出文件位于 /tmp/tracing.out 中,其中是 shell 脚本进程。 20 秒的目的是允许用户空间活动发生——此时只是开始大量的 UDP 活动。您也可以从上面的脚本中删除“echo udp_* >/debug/tracing/set_ftrace_filter”,因为默认是跟踪所有内容。

【讨论】:

  • 这个函数不是内核的入口点,在内核决定切换到这个函数之前有很多步骤!
  • 当然这些不是入口点——有很多。但 OP 要求 UDP 起点。
  • 经过一些更改,现在上面的跟踪输出列表都是内核内部的执行点。 UDP 处理的“入口点”非常模糊,具体取决于您的定义,但函数列表仍然显示在上面。
【解决方案2】:

linux 网络堆栈是内核的一大块,您需要花一些时间研究它。 我认为这本书可能会有所帮助(专注于旧内核 2.4 和 2.6,但最新内核 3.x 的逻辑保持不变):

Understanding Linux Network Internals

The Linux Networking Architecture - Design and Implementation of Network Protocols in the Linux Kernel

您也可以查看以下链接:

http://e-university.wisdomjobs.com/linux/chapter-189-277/sending-the-data-from-the-socket-through-udp-and-tcp.html

http://www.linuxfoundation.org/collaborate/workgroups/networking/kernel_flow

http://wiki.openwrt.org/doc/networking/praxis

http://www.ibm.com/developerworks/linux/library/l-linux-networking-stack/?ca=dgr-lnxw01lnxNetStack

http://gicl.cs.drexel.edu/people/sevy/network/Linux_network_stack_walkthrough.html

您还需要浏览内核源代码:

http://lxr.linux.no/#linux+v3.7.3/

使用此功能开始您的网络子系统之路: ip_rcv 在收到数据包时调用。 然后调用其他函数(ip_rcv_finiship_local_deliverip_local_deliver_finish=> 这个函数负责选择好的传输层)

【讨论】:

  • 所提供的链接解释实际上都没有说“UDP”...... :-)。
【解决方案3】:

如果您喜欢更直观的方式,请尝试flame-grahps。下面是一个 UDP 传输流示例(使用 netperf 传输 UDP 数据包):

这是在 udp_send_skb 上放大的同一张图:

您可以对内核中的任何相关流程执行相同的操作。您还可以搜索特定功能或关键字并放大/缩小。这也让您了解流程中较重的功能。

希望这会有所帮助。

【讨论】:

    【解决方案4】:

    这个链接也不错。它谈到了 udp 和底层 IP、NIC 等:

    https://blog.packagecloud.io/eng/2017/02/06/monitoring-tuning-linux-networking-stack-sending-data/

    【讨论】:

    • 请为任何链接添加上下文,以便您的答案是独立的,这意味着答案需要在答案本身中。见"Provide context for links"。如果您可以在此处用自己的话回答问题并仅作为参考链接,那将是更好的选择。
    猜你喜欢
    • 2015-08-06
    • 2010-12-21
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 2013-08-22
    • 2020-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多