[Linux] Tracing Linux Networking with DTrace on Oracle Linux

原文はこちら
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を使用すると、複数のサブシステムにアクセスできます。例えば、以下のような情報を取得できます。
    • パケットを受信するときに割り込みをどれぐらい効率的に合体させているのか
    • どのロックがネットワーク受信パスでホットな状態なのか
    特にクラウド環境では、ネットワークの振る舞いから他のサブシステムや抽象に結びつけて全体像を作り上げることが不可欠です。人々は "ネットワーク"を責めたがりますが、DTraceを使用すると、コストが本当にどこで発生しているかを確認できます。

Socket layer: syscall provider - available since UEK2

他のオペレーティングシステムと同様に、syscallプロバイダも利用でき、ネットワーク関連のシステムコール(sendto、sendmsg、sendmmsg、recvfrom、recvmsg、recvmmsg)をトレースできます。
以下は、実行可能な単位で送信されるバイトトレースの簡単な例です。情報を収集したら、Ctrl+Cキーを押します。
# 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
これがDTraceのone-linerです。一つずつ見ていきましょう。
  • -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のサイズがわかります。
まとめると、one-linerでは「システムコールsendto()経由で送信されたバイト数の合計を表示し、各プログラム名での合計を収集」しています(execnameは組み込み済みの変数で、現在のプロセス実行可能ファイル名を表す)。
もちろん、これらはリクエストであり、失敗するものもあります。 再度使用したプローブは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ステートマシン遷移と接続確立マイルストンもトレースします。
# 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
以下は、どのシステム(リモートIP)への接続を拒否しているのか、どのポートに接続しようとしているのか、という例です。
# 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
この例を生成するために、別のウィンドウでポート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を参照してください。

ほとんどの場合、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プロバイダは送信、受信、インバウンド/アウトバウンドのパケットドロップをトレースします。
 # 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
IPプロバイダにおける引数は以下のようです。
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の範囲にあったことがわかります。
# 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
将来のエントリで、fbtプロバイダやperfプロバイダを使った例を説明する予定にしています。

0 件のコメント:

コメントを投稿