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
0 件のコメント:
コメントを投稿