原文はこちら
https://blogs.oracle.com/linuxkernel/tracing-linux-networking-with-dtrace-on-oracle-linux
Alan Maguireのこの記事では、DTraceを使用した一般的なネットワーク関連のシステムコールを調査方法を紹介します。DTraceは、ユーザーおよびカーネルプロセスを理解するための強力なトレースツールです。
私たちは、DTraceのOracle Linuxのネットワーキングに対するサポートは着実に追加されています。これらのプローブを使ってネットワークの動作をよりよく理解する方法を見ていきましょう。ネットワークスタックの動的トレースでどのようなサポートが利用できるかを簡単に見てみましょう。
しかし、詳細を知る前に、なぜDTraceを使うのがいいのでしょうか。ネットワークの領域で十分なツールがあるのではないでしょうか。私がDTraceを使用する理由は次のとおりです。
以下は、実行可能な単位で送信されるバイトトレースの簡単な例です。情報を収集したら、Ctrl+Cキーを押します。
もちろん、これらはリクエストであり、失敗するものもあります。 再度使用したプローブはsyscall::sendto:entryでした。対応するsyscall::sendto:returnもあります。DTraceの一般的なパターンは、:entryから:returnまでの時間を測定します。
ほとんどの場合、Solarisとの互換性は維持されています、本当に必要なのが見つからない場合はお知らせください。様々な引数がどのように見えるかご紹介しましょう。arg0ではなくargs[0]を使って、安定した、変換済み引数へアクセスしようとしていることをDTraceに知らせています。素の引数はarg0、arg1などを使って引き続き利用できます。
IPプロバイダは送信、受信、インバウンド/アウトバウンドのパケットドロップをトレースします。
https://blogs.oracle.com/linuxkernel/tracing-linux-networking-with-dtrace-on-oracle-linux
Alan Maguireのこの記事では、DTraceを使用した一般的なネットワーク関連のシステムコールを調査方法を紹介します。DTraceは、ユーザーおよびカーネルプロセスを理解するための強力なトレースツールです。
私たちは、DTraceのOracle Linuxのネットワーキングに対するサポートは着実に追加されています。これらのプローブを使ってネットワークの動作をよりよく理解する方法を見ていきましょう。ネットワークスタックの動的トレースでどのようなサポートが利用できるかを簡単に見てみましょう。
しかし、詳細を知る前に、なぜDTraceを使うのがいいのでしょうか。ネットワークの領域で十分なツールがあるのではないでしょうか。私がDTraceを使用する理由は次のとおりです。
- DTraceは実稼動環境で安全でありつつ、制約がありません。つまり、何かを見つけたいのであれば、通常はそれを行う方法があります。最も重要なのは、システムがパニックを起こさずに実行できることです。当然のことながら、その困難な部分が、これらの質問からDTraceが理解する問い合わせになっています。私は、次回以後のエントリでそうする方法についていくつかの有用なヒントを提供できると思っています。
- DTraceを使用すると、複数のサブシステムにアクセスできます。例えば、以下のような情報を取得できます。
- パケットを受信するときに割り込みをどれぐらい効率的に合体させているのか
- どのロックがネットワーク受信パスでホットな状態なのか
Socket layer: syscall provider - available since UEK2
他のオペレーティングシステムと同様に、syscallプロバイダも利用でき、ネットワーク関連のシステムコール(sendto、sendmsg、sendmmsg、recvfrom、recvmsg、recvmmsg)をトレースできます。以下は、実行可能な単位で送信されるバイトトレースの簡単な例です。情報を収集したら、Ctrl+Cキーを押します。
これがDTraceのone-linerです。一つずつ見ていきましょう。# dtrace -n 'syscall::sendto:entry { @c[execname] = sum(arg2); }'
dtrace: description 'syscall::sendto:entry ' matched 1 probe
^C
DNS Resolver #6 65
ping 192
Socket Thread 2006
vpnagentd 3872
- -nオプションは、DTraceスクリプトを使用するのではなく、プローブを直接指定していることを示しています(DTraceスクリプトを使用するには、 "dtrace -s <scriptname>"を使用します)。
- プローブは4要素を記述し、各要素は ":"で区切ります。最初の要素は、私たちが使用しているDTraceサブシステムのプロバイダです。今回の場合、syscall(システムコール)です。もう1つはモジュールです。これは他のDTraceプロバイダには関係しますが、ここでは使用できません(Linuxでは常に "vmlinux"ですので空白にしておきます)。 3番目は関数です - システムコールプロバイダの場合はシステムコール名です。最後にプローブ名です。システムコールごとに、システムコールの要求/完了に対応するエントリとリターンの2つのプローブがあります。
- 次は、中括弧に含まれるアクションです。DTraceコードは、"probe/predicate/{action}"の形式をとります。この場合、述語はありませんが、もし述語がある場合、ボディが実行されたか否かを判断します。続いてアクションを説明します。
- ここでは、集計変数 "c"を使用しています。集計は "@"記号で表されています。アグリゲーションでは、角括弧の間に複数のキーを指定でき、sum()、count()、avg()などのいずれかの集計関数を使用して、さまざまなキーセットに関連付けられた値を計算します。アグリゲーションは効率的にカーネル内で収集されます。この例では、sendto()の3個目の引数であるarg2のSummationを取得しています。マニュアルを見ればarg2のサイズがわかります。
もちろん、これらはリクエストであり、失敗するものもあります。 再度使用したプローブはsyscall::sendto:entryでした。対応するsyscall::sendto:returnもあります。DTraceの一般的なパターンは、:entryから:returnまでの時間を測定します。
Layer 4 (Transport layer): TCP, UDP providers - available since UEK4QU5
Linuxの場合(Solarisでも同様です)、TCPやUDPのトランスポートレベル・プロバイダがあります。これらは送受信イベントをトレースし、TCPについてはTCPステートマシン遷移と接続確立マイルストンもトレースします。以下は、どのシステム(リモートIP)への接続を拒否しているのか、どのポートに接続しようとしているのか、という例です。# dtrace -l -P udp
ID PROVIDER MODULE FUNCTION NAME
1836 udp vmlinux udp_send_skb send
1838 udp vmlinux udp_recvmsg receive
1840 udp vmlinux udp_queue_rcv_skb receive
1868 udp vmlinux udp_v6_send_skb send
1869 udp vmlinux udpv6_recvmsg receive
1871 udp vmlinux udpv6_queue_rcv_skb receive
# dtrace -l -P tcp
ID PROVIDER MODULE FUNCTION NAME
1818 tcp vmlinux tcp_set_state state-change
1819 tcp vmlinux tcp_conn_request state-change
1820 tcp vmlinux tcp_finish_connect connect-established
1821 tcp vmlinux tcp_rcv_state_process accept-established
1822 tcp vmlinux tcp_rcv_state_process connect-refused
1823 tcp vmlinux tcp_transmit_skb send
1824 tcp vmlinux tcp_transmit_skb connect-request
1825 tcp vmlinux tcp_connect state-change
1826 tcp vmlinux tcp_v4_send_ack send
1827 tcp vmlinux tcp_v4_send_reset send
1828 tcp vmlinux tcp_v4_send_reset accept-refused
1829 tcp vmlinux tcp_v4_send_synack send
1830 tcp vmlinux tcp_v4_rcv receive
1831 tcp vmlinux tcp_time_wait state-change
1882 tcp vmlinux tcp_v6_send_response send
1883 tcp vmlinux tcp_v6_send_response accept-refused
1884 tcp vmlinux tcp_v6_send_synack send
1885 tcp vmlinux tcp_v6_rcv receive
この例を生成するために、別のウィンドウでポート7に対しローカルにtelnetで接続しました。ポート7は閉じられているため、1つの接続が拒否されています。TCP、UDP、およびIPプロバイダーはすべて静的定義トレース(SDT)プロバイダーです。これらの考え方は、絶えず変化する機能のエントリやリターンに位置するプローブを作成して変化するデータ構造から情報を収集しようとするのではなく、関心のあるイベントや、これらのイベントが発生するコードの各ポイントを定義して、静的プローブを配置します。たとえば、tcp:::sendプローブがtcp_v4_send_reset、tcp_v4_send_ackなどにあることがわかります。重要なのは、これらのプローブは、OS固有の構造をとり、DTraceコンシューマが信頼できる安定した引数に変換する安定したトランスレータを定義します。 Oracle Linuxの関連する定義を参照するには、/usr/lib64/dtrace/4.1/tcp.d、udp.d、ip.dを参照してください。# dtrace -n 'tcp:::accept-refused { @c[args[2]->ip_daddr, args[4]->tcp_sport] = count(); }'
dtrace: description 'tcp:::accept-refused ' matched 2 probes
^C
127.0.0.1 7 1
ほとんどの場合、Solarisとの互換性は維持されています、本当に必要なのが見つからない場合はお知らせください。様々な引数がどのように見えるかご紹介しましょう。arg0ではなくargs[0]を使って、安定した、変換済み引数へアクセスしようとしていることをDTraceに知らせています。素の引数はarg0、arg1などを使って引き続き利用できます。
args[0] - pktinfo_t * [packet information]
args[1] - csinfo_t * [ connection information]
args[2] - ipinfo_t * [IP protocol information]
args[3] - tcpsinfo_t * for TCP, udpsinfo_t * for UDP [TCP/UDP state information]
args[4] - tcpinfo_t * for TCP, udpinfo_t * for UDP [TCP/UDP header information]
Layer 3 (IP provider) - available since UEK4QU4
IPプロバイダは送信、受信、インバウンド/アウトバウンドのパケットドロップをトレースします。
IPプロバイダにおける引数は以下のようです。# dtrace -l -P ip
ID PROVIDER MODULE FUNCTION NAME
1839 ip vmlinux ip_rcv_finish drop-in
1840 ip vmlinux ip_local_deliver receive
1841 ip vmlinux ip_rcv drop-in
1842 ip vmlinux __ip_append_data drop-out
1843 ip vmlinux __ip_local_out_sk send
1844 ip vmlinux ip_append_page drop-out
1845 ip vmlinux ip_send_skb drop-out
1861 ip vmlinux raw_sendmsg send
1878 ip vmlinux __ip6_flush_pending_frames drop-out
1879 ip vmlinux ip6_xmit send
1880 ip vmlinux ip6_xmit drop-out
1881 ip vmlinux ip6_finish_output2 drop-out
1882 ip vmlinux __ip6_append_data drop-out
1883 ip vmlinux ip6_forward drop-out
1884 ip vmlinux ip6_output drop-out
1885 ip vmlinux ip6_send_skb drop-out
1886 ip vmlinux ip6_input_finish drop-in
1887 ip vmlinux ipv6_rcv drop-in
1888 ip vmlinux ip6_input receive
1895 ip vmlinux ndisc_send_skb send
1900 ip vmlinux rawv6_sendmsg send
1903 ip vmlinux mld_sendpack send
1904 ip vmlinux mld_sendpack drop-out
1905 ip vmlinux igmp6_send send
1906 ip vmlinux igmp6_send drop-out
1923 ip vmlinux __ip6_local_out_sk send
args[0] - pktinfo_t * [packet information]
args[1] - csinfo_t * [connection information]
args[2] - ipinfo_t * [IP protocol information]
args[3] - ifinfo_t * [IP interface info]
args[4] - ipv4info_t * [IPv6 header info if IPv6 packet]
args[5] - ipv6info_t * [IPv6 header info if IPv6 packet]
Other
Oracle LinuxのDTraceには、perfイベントをトレースするperfプロバイダが含まれています。もちろん、関数境界トレース(fbt)も利用できます。以下は、関数境界トレースを使用してソケットバッファ(struct sk_buff)の割り当てサイズを取得する例です。sk_buffはネットワークデータのキー構造です。ここでは、2のべき乗のバケット(0-1、1-2、2-4など)に入る個数を調べています。これはquantize()という集約アクションです。例えば、大多数が2048〜4096の範囲にあったことがわかります。将来のエントリで、fbtプロバイダやperfプロバイダを使った例を説明する予定にしています。# dtrace -n 'fbt::__alloc_skb:entry { @size = quantize(arg0); }'
dtrace: description 'fbt::__alloc_skb:entry ' matched 1 probe
^C
value ------------- Distribution ------------- count
-1 | 0
0 | 80
1 | 3
2 | 0
4 | 137
8 | 988
16 |@@ 5719
32 |@@@@@ 10977
64 | 779
128 |@@@ 6805
256 |@@@@@@@@@@@ 25462
512 | 508
1024 |@@ 5108
2048 |@@@@@@@@@@@@@@@@ 39011
4096 | 8
8192 | 0
16384 | 16
32768 | 0