Linux カーネルで UDP パケットのパスを見つけたいです。このために、いくつかのドキュメントを読みたいと思います(これまでのところ、これはTCP用です)。それを確認するために、関連するカーネル関数にprintkステートメントをいくつか入れます。これを行うには、カーネル コードを再コンパイルします。
これはそれについて行く方法ですか?提案/参照はありますか?
Linux カーネルで UDP パケットのパスを見つけたいです。このために、いくつかのドキュメントを読みたいと思います(これまでのところ、これはTCP用です)。それを確認するために、関連するカーネル関数にprintkステートメントをいくつか入れます。これを行うには、カーネル コードを再コンパイルします。
これはそれについて行く方法ですか?提案/参照はありますか?
具体的に質問に答えて、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 | }
また、ネットワークコードの出力については、いくつかのスニペットが以下に抽出されています。
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では関数グラフと呼ばれます。
Linuxカーネル関数をftracefunction_graphtracerで使用できるようにする方法は?
そして、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内にあります。ここで、はシェルスクリプトプロセスです。20秒の目的は、ユーザースペースアクティビティを実行できるようにすることです。この時点で多くのUDPアクティビティを開始するだけです。デフォルトではすべてをトレースするため、上記のスクリプトから「 echo udp_ *> / debug / traceing/set_ftrace_filter 」を削除することもできます。
Linux のネットワーク スタックはカーネルの大きな部分を占めており、その研究に時間を費やす必要があります。この本が役立つと思います (古いカーネル 2.4 と 2.6 に焦点を当てていますが、最新のカーネル 3.x でもロジックは同じです):
The Linux Networking Architecture - Linux カーネルにおけるネットワーク プロトコルの設計と実装
このリンクをチェックアウトすることもできます:
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_finish
、ip_local_deliver
および ip_local_deliver_finish
=> この関数は、適切なトランスポート層を選択する責任があります)
より視覚的な方法を好む場合は、flame-graphsを試してください。UDP 送信フローの例を次に示します (netperf を使用して UDP パケットを送信します)。
そして、これは udp_send_skb を拡大した同じグラフです。
カーネル内の関連するフローについても同じことができます。特定の機能やキーワードで検索したり、ズームイン/ズームアウトしたりすることもできます。これにより、フロー内のより重い関数についてのアイデアも得られます。
お役に立てれば。