ネットワークを調査する 50 の方法

はじめに

今回は Solaris でネットワークの性能や障害を調査するコマンドをご紹介したいと思います。私が普段よく使用する物を中心に、用途別に大体 50 種類の手順をまとめました。

ネットワークの解析方法

ネットワークインターフェイスの一覧を表示する

ifconfig -a

現在使用可能なネットワークインターフェイスの一覧は "ifconfig -a" で調べる事が出来ます。インターフェイス名、MTU、IP アドレス、ネットマスク等の情報も得る事が出来ます。

 % ifconfig -a
 lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1
         inet 127.0.0.1 netmask ff000000 
 e1000g0: flags=201000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 2
         inet 10.16.67.5 netmask ffff0000 broadcast 10.16.255.255

root ユーザで実行した場合は MAC アドレスも表示されます。

 # ifconfig -a
 lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1
         inet 127.0.0.1 netmask ff000000 
 e1000g0: flags=201000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 2
         inet 10.16.67.5 netmask ffff0000 broadcast 10.16.255.255
         ether 0:23:8b:64:88:60 

"ifconfig -a plumb" で全てのインターフェイスを有効にしてから "ifconfig -a" を実行すると、システムで利用可能な全てのインターフェイスを表示する事が出来ます。

 # ifconfig -a plumb 
 ifconfig: SIOCSLIFNAME for ip: e1000g0: already exists
 # ifconfig -a
 lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1
         inet 127.0.0.1 netmask ff000000 
 e1000g0: flags=201000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 2
         inet 10.16.67.5 netmask ffff0000 broadcast 10.16.255.255
         ether 0:23:8b:64:88:60 
 e1000g1: flags=201000842<BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 3
         inet 0.0.0.0 netmask 0 
         ether 0:23:8b:64:88:61 
 e1000g2: flags=201000842<BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 4
         inet 0.0.0.0 netmask 0 
         ether 0:23:8b:64:88:62 
 e1000g3: flags=201000842<BROADCAST,RUNNING,MULTICAST,IPv4,CoS> mtu 1500 index 5
         inet 0.0.0.0 netmask 0 
         ether 0:23:8b:64:88:63 

dladm show-dev

"dladm show-dev" コマンドでもインターフェイスの一覧を表示する事が出来ます。リンクの状態やリンクスピード、デュプレックスの情報も入手出来ます。また、有効になっていないインターフェイスについても見る事が出来ます。dladm コマンドは root ユーザで実行する必要があります。

 # dladm show-dev
 e1000g0         link: up        speed: 100   Mbps       duplex: full
 e1000g1         link: down      speed: 0     Mbps       duplex: half
 e1000g2         link: down      speed: 0     Mbps       duplex: half
 e1000g3         link: down      speed: 0     Mbps       duplex: half

dladm show-link

"dladm show-link" をすると、リンクタイプや MTU を表示する事が出来ます。

 # dladm show-link
 e1000g0         type: non-vlan  mtu: 1500       device: e1000g0
 e1000g1         type: non-vlan  mtu: 1500       device: e1000g1
 e1000g2         type: non-vlan  mtu: 1500       device: e1000g2
 e1000g3         type: non-vlan  mtu: 1500       device: e1000g3

インターフェイス名のみを取得するスクリプト

シェルスクリプトで NIC の名前だけをリストにして抜き出せると便利です。以下の一行を実行すると ${NIC} にリンクアップしているインターフェイスの名前がスペース区切りで格納されます。

 # NIC=`dladm show-dev -p | grep 'link=up' | awk '{printf "%s ", $1}'`

これはスクリプトの中で使うと便利です。以下のスクリプトでは各インターフェイスについて "dladm show-dev -s -i 1 <NIC>" を実行して統計情報をログに保存しています。

 #!/bin/sh
 NIC=`dladm show-dev -p | grep 'link=up' | awk '{printf "%s ", $1}'`
 for i in ${NIC}
  do dladm show-dev -s -i 1 ${i} > dladm-${i}.log &
 done

インターフェイスの状態を調べる

インターフェイスがリンクアップしているかどうかは "kstat -p ':::link_up'" でも調べられます。1 がリンクアップです。

 # kstat -p ':::link_up'
 e1000g:0:mac:link_up    1
 e1000g:1:mac:link_up    0
 e1000g:2:mac:link_up    0
 e1000g:3:mac:link_up    0

インターフェイスのリンクスピードは "kstat -p ':::link_speed'" でも調べられます。単位は Mbps です。

 # kstat -p ':::link_speed'
 e1000g:0:statistics:link_speed  100
 e1000g:1:statistics:link_speed  0
 e1000g:2:statistics:link_speed  0
 e1000g:3:statistics:link_speed  0

インターフェイスのデュプレックスは "kstat -p ':::duplex'" でも調べられます。2 が full duplex です。

 # kstat -p ':::link_duplex'
 e1000g:0:mac:link_duplex        2
 e1000g:1:mac:link_duplex        1
 e1000g:2:mac:link_duplex        1
 e1000g:3:mac:link_duplex        1

ネットワークセッションの一覧を表示する

netstat -a

"netstat -a" コマンドを使用すると現在のソケットの状態を調べる事が出来ます。State が "ESTABLISHED" になっているソケットはセッションが確立している接続です。

 # netstat -a 
 ...
 TCP: IPv4
    Local Address        Remote Address    Swind Send-Q Rwind Recv-Q    State
 -------------------- -------------------- ----- ------ ----- ------ -----------
       \*.\*                  \*.\*                0      0 49152      0 IDLE
       \*.sunrpc             \*.\*                0      0 49152      0 LISTEN
       \*.\*                  \*.\*                0      0 49152      0 IDLE
       \*.32771              \*.\*                0      0 49152      0 LISTEN
       \*.32772              \*.\*                0      0 49152      0 LISTEN
 ...
 sanuki05.5001        10.16.62.7.35163     49640      0 49640      0 ESTABLISHED
 sanuki05.5001        10.16.62.7.35164     49640      0 49640      0 ESTABLISHED
 sanuki05.5001        10.16.62.7.35165     49640      0 49640      0 ESTABLISHED
 sanuki05.5001        10.16.62.7.35166     49640      0 49640      0 ESTABLISHED
 sanuki05.5001        10.16.62.7.35167     49640      0 49640      0 ESTABLISHED

"netstat -aP tcp -f inet" を実行すると、IPv4 で TCP を使用しているソケットだけを抜き出す事が出来ます。

 # netstat -aP tcp -f inet
 
 TCP: IPv4
    Local Address        Remote Address    Swind Send-Q Rwind Recv-Q    State
 -------------------- -------------------- ----- ------ ----- ------ -----------
       \*.\*                  \*.\*                0      0 49152      0 IDLE
       \*.sunrpc             \*.\*                0      0 49152      0 LISTEN
       \*.\*                  \*.\*                0      0 49152      0 IDLE
       \*.32771              \*.\*                0      0 49152      0 LISTEN
       \*.32772              \*.\*                0      0 49152      0 LISTEN
       \*.lockd              \*.\*                0      0 49152      0 LISTEN
 ...

セッション数を調べる

netstat -a | grep ESTAB | wc -l

"netstat -a | grep ESTAB | wc -l" を実行すると、現在繋がっているネットワークセッションの本数を調べる事が出来ます。以下の様に while 分で回せば、毎秒のセッション数の増減を記録する事が出来ます。以下の例では 34 本のセッションが張られています。

 # while :; do netstat -a | grep ESTAB | wc -l; sleep 1; done
       34
       34
       34

"netstat -a | grep telnet | grep ESTAB | wc -l" を実行すると、telnet のセッションだけを抜き出す事が出来ます。同じ様に while で回せば、telnet セッションの増減を記録する事が出来ます。telnet 以外にも http や 1521 番の Oracle のセッションだけを抜き出す事も可能です。以下の例では 8 本の telnet セッションが張られています。

 # while :; do netstat -a | grep telnet | grep ESTAB | wc -l; sleep 1; done
        8
        8
        8

kstat -p tcp:0:tcp:currEstab 1

"kstat -p tcp:0:tcp:currEstab 1" を実行すると TCP のセッション数を出力します。この値は /usr/src/uts/common/inet/tcp/tcp.c の tcp_kstat_update() 関数で集計されています。

 % kstat -p tcp:0:tcp:currEstab 1
 tcp:0:tcp:currEstab     4
 
 tcp:0:tcp:currEstab     4
 
 tcp:0:tcp:currEstab     3

スループットを調べる

dladm show-dev -s -i 1 <NIC>

"dladm show-dev -s -i 1 <NIC>" を実行すると、受信したパケット数(ipackets)、受信したデータのバイト数(rbytes)、受信の際に発生したエラーの数(ierrors)、送信したパケット数(opackets)、送信したデータのバイト数(obytes)、送信の際に発生したエラーの数(oerrors)を 1 秒毎に表示する事が出来ます。最初の出力はブートしてからの累積値です。

 # dladm show-dev -s -i 1 e1000g0
                 ipackets  rbytes         ierrors opackets        obytes      oerrors
 e1000g0         4048080   2168050372  0       611314    120697887   0       
                 ipackets  rbytes         ierrors opackets        obytes      oerrors
 e1000g0         5         320         0       2         366         0       
                 ipackets  rbytes         ierrors opackets        obytes      oerrors
 e1000g0         6         384         0       2         280         0       

netstat -i -I <NIC> 1

"netstat -i -I <NIC> 1" でもネットワークのスループットを表示する事が出来ますが、送受信バイト数を見る事は出来ません。出来る限り dladm コマンドをお使い下さい。

 # netstat -i -I e1000g0 1
     input   e1000g    output       input  (Total)    output
 packets errs  packets errs  colls  packets errs  packets errs  colls 
 4048518 0     611396  0     0      4048688 0     611566  0     0     
 3       0     1       0     0      3       0     1       0     0     
 4       0     2       0     0      4       0     2       0     0     

kstat -p '<NIC>:::\*bytes' 1

"kstat -p '<NIC>:::\*bytes' 1" を実行すると送受信バイト数の累積を表示する事が出来ます。これが dladm や netstat の出力の元データです。kstat の引数はインターフェイス毎に多少異なります。kstat のデータは殆ど整形されていない生データなので加工してお使い下さい。

 # kstat -p 'e1000g:0:e1000g0:\*bytes' 1
 e1000g:0:e1000g0:obytes 120717403
 e1000g:0:e1000g0:rbytes 2168116829
 
 e1000g:0:e1000g0:obytes 120717532
 e1000g:0:e1000g0:rbytes 2168117213
 
 e1000g:0:e1000g0:obytes 120717789
 e1000g:0:e1000g0:rbytes 2168117597

"kstat -p '<NIC>:::\*packets' 1" を実行すると送受信パケット数の累積を表示する事が出来ます。kstat には他にも便利な統計情報が入っていますので、是非お試し下さい。

 # kstat -p 'e1000g:0:e1000g0:\*packets' 1
 e1000g:0:e1000g0:ipackets       4050305
 e1000g:0:e1000g0:opackets       611558
 
 e1000g:0:e1000g0:ipackets       4050309
 e1000g:0:e1000g0:opackets       611559
 
 e1000g:0:e1000g0:ipackets       4050315
 e1000g:0:e1000g0:opackets       611561

ネットワークインターフェイスの CPU 使用率を見る

intrstat 1

"intrstat 1" を実行するとデバイスが発生させたインタラプトの処理に使用している CPU の割合を調べる事が出来ます。以下の例では e1000g0 インターフェイスが CPU 6 番を 5.0% 使用している事が分かります。

 # intrstat 1
 ...
       device |      cpu0 %tim      cpu1 %tim      cpu2 %tim      cpu3 %tim
 -------------+------------------------------------------------------------
       ahci#0 |         0  0.0         0  0.0         0  0.0         0  0.0
     e1000g#0 |         0  0.0         0  0.0         0  0.0         0  0.0
     e1000g#2 |         0  0.0         0  0.0         0  0.0         0  0.0
       ehci#0 |         0  0.0         0  0.0         0  0.0         0  0.0
       uhci#0 |         0  0.0         0  0.0         0  0.0         0  0.0
       uhci#1 |         0  0.0         0  0.0         0  0.0         0  0.0
       uhci#2 |         0  0.0         0  0.0         0  0.0         0  0.0
       uhci#3 |         0  0.0         0  0.0         0  0.0         0  0.0
 
       device |      cpu4 %tim      cpu5 %tim      cpu6 %tim      cpu7 %tim
 -------------+------------------------------------------------------------
       ahci#0 |         0  0.0         2  0.0         0  0.0         0  0.0
     e1000g#0 |         0  0.0         0  0.0      8204  5.0         0  0.0
     e1000g#2 |         0  0.0         0  0.0         1  0.0         0  0.0
       ehci#0 |        18  0.0         0  0.0         0  0.0         0  0.0
       uhci#0 |        18  0.0         0  0.0         0  0.0         0  0.0
       uhci#1 |         0  0.0         1  0.0         0  0.0         0  0.0
       uhci#2 |         0  0.0         1  0.0         0  0.0         0  0.0
       uhci#3 |         0  0.0         2  0.0         0  0.0         0  0.0

ネットワークインターフェイスの統計情報を見る

kstat -p '<NIC>:::' 1

"kstat -p '<NIC>:<Instance>::' 1" を実行すると、カーネルに保存してあるインターフェイスの情報を表示する事が出来ます。kstat には性能に関する情報を含め、様々なデータが記録されています。<Instance> は ifconfig コマンド等で表示される NIC のインスタンス番号です。以下の例では e1000g0 インターフェイスの統計情報を表示しています。出力はそれぞれ重要な意味を持っています。例えば norcvbuf が発生している場合は受信用のバッファが不足している事を意味しています。

 # kstat -p 'e1000g:0::'
 e1000g:0:e1000g0:brdcstrcv      2621877
 e1000g:0:e1000g0:brdcstxmt      4542
 e1000g:0:e1000g0:class  net
 e1000g:0:e1000g0:collisions     0
 e1000g:0:e1000g0:crtime 135.093656493
 e1000g:0:e1000g0:ierrors        0
 e1000g:0:e1000g0:ifspeed        100000000
 e1000g:0:e1000g0:ipackets       4533601
 e1000g:0:e1000g0:ipackets64     4533601
 e1000g:0:e1000g0:multircv       21570
 e1000g:0:e1000g0:multixmt       0
 e1000g:0:e1000g0:norcvbuf       0
 e1000g:0:e1000g0:noxmtbuf       0
 e1000g:0:e1000g0:obytes 135842713
 e1000g:0:e1000g0:obytes64       135842713
 e1000g:0:e1000g0:oerrors        0
 e1000g:0:e1000g0:opackets       846546
 e1000g:0:e1000g0:opackets64     846546
 e1000g:0:e1000g0:rbytes 2884822219
 e1000g:0:e1000g0:rbytes64       2884822219
 ...

nxge の DMA Channel の統計情報を取得する

nxge インターフェイスは複数の転送経路にデータを分散する事で高いスループットを達成しています。データの分散状況は kstat コマンドを使用して調べる事が出来ます。kstat の出力の各行が転送経路です。一番右側の数値がその経路を通って転送されたパケット数の累積値です。値の増加に偏りがある場合はインターフェイスの設定を見直して下さい。

 # kstat -p 'nxge:1::\*dc_packets' 1
 nxge:1:RDC Channel 0 Stats:rdc_packets  17920164
 nxge:1:RDC Channel 1 Stats:rdc_packets  17876325
 nxge:1:RDC Channel 2 Stats:rdc_packets  18551372
 nxge:1:RDC Channel 3 Stats:rdc_packets  17262833
 nxge:1:RDC Channel 4 Stats:rdc_packets  17916873
 nxge:1:RDC Channel 5 Stats:rdc_packets  18427140
 nxge:1:RDC Channel 6 Stats:rdc_packets  18380673
 nxge:1:RDC Channel 7 Stats:rdc_packets  18262768
 nxge:1:TDC Channel 0 Stats:tdc_packets  25398140
 nxge:1:TDC Channel 1 Stats:tdc_packets  26289370
 nxge:1:TDC Channel 2 Stats:tdc_packets  25947133
 nxge:1:TDC Channel 3 Stats:tdc_packets  25353460
 nxge:1:TDC Channel 4 Stats:tdc_packets  27044560
 nxge:1:TDC Channel 5 Stats:tdc_packets  26080875
 nxge:1:TDC Channel 6 Stats:tdc_packets  25467176
 nxge:1:TDC Channel 7 Stats:tdc_packets  25782669
 ...

ネットワークインターフェイスのパラメータを調べる

ndd -get /dev/<NIC>

"ndd -get /dev/<NIC> \\?" を実行するとインターフェイスのパラメータ一の一部を取得する事が出来ます。

 # ndd -get /dev/e1000g0 \\?
 ?                             (read only)
 autoneg_cap                   (read only)
 pause_cap                     (read only)
 asym_pause_cap                (read only)
 1000fdx_cap                   (read only)
 1000hdx_cap                   (read only)
 100T4_cap                     (read only)
 100fdx_cap                    (read only)
 100hdx_cap                    (read only)
 10fdx_cap                     (read only)
 10hdx_cap                     (read only)
 adv_autoneg_cap               (read and write)
 ...

パラメータの値を取得する場合はパラメータ名を指定します。"(read and write)" と表示されているパラメータは -set オプションを使用して値を設定する事も可能です。

 # ndd -get /dev/e1000g0 max_num_rcv_packets
 128

TCP の統計情報を見る

netstat -sP tcp 1

"netstat -sP tcp 1" を実行すると TCP の統計情報を表示する事が出来ます。もし tcpListenDrop が発生していたら要対応です。

 # netstat -sP tcp 1
 ...
 TCP     tcpRtoAlgorithm     =     0     tcpRtoMin           =   400
         tcpRtoMax           = 60000     tcpMaxConn          =    -1
         tcpActiveOpens      =     0     tcpPassiveOpens     =     0
         tcpAttemptFails     =     0     tcpEstabResets      =     0
         tcpCurrEstab        =    23     tcpOutSegs          =    20
         tcpOutDataSegs      =    16     tcpOutDataBytes     =  5568
         tcpRetransSegs      =     0     tcpRetransBytes     =     0
         tcpOutAck           =     4     tcpOutAckDelayed    =     2
         tcpOutUrg           =     0     tcpOutWinUpdate     =     0
         tcpOutWinProbe      =     0     tcpOutControl       =     0
         tcpOutRsts          =     0     tcpOutFastRetrans   =     0
         tcpInSegs           =    15
         tcpInAckSegs        =     9     tcpInAckBytes       =  5568
         tcpInDupAck         =     0     tcpInAckUnsent      =     0
         tcpInInorderSegs    =     6     tcpInInorderBytes   =  3122
         tcpInUnorderSegs    =     0     tcpInUnorderBytes   =     0
         tcpInDupSegs        =     0     tcpInDupBytes       =     0
         tcpInPartDupSegs    =     0     tcpInPartDupBytes   =     0
         tcpInPastWinSegs    =     0     tcpInPastWinBytes   =     0
         tcpInWinProbe       =     0     tcpInWinUpdate      =     0
         tcpInClosed         =     0     tcpRttNoUpdate      =     0
         tcpRttUpdate        =     9     tcpTimRetrans       =     0
         tcpTimRetransDrop   =     0     tcpTimKeepalive     =     0
         tcpTimKeepaliveProbe=     0     tcpTimKeepaliveDrop =     0
         tcpListenDrop       =     0     tcpListenDropQ0     =     0
         tcpHalfOpenDrop     =     0     tcpOutSackRetrans   =     0

kstat -p 'tcp:0::'

"kstat -p 'tcp:0::' 1" を実行すると TCP に関する統計情報を出力する事が出来ます。このコマンドで取得出来るデータが "netstat -sP tcp 1" の元になっています。

 % kstat -p 'tcp:0::' 1
 tcp:0:tcp:activeOpens   67462
 tcp:0:tcp:attemptFails  445
 tcp:0:tcp:class mib2
 tcp:0:tcp:connTableSize 72
 tcp:0:tcp:connTableSize6        96
 tcp:0:tcp:crtime        105.965466
 tcp:0:tcp:currEstab     23
 tcp:0:tcp:estabResets   56804
 ...

tcpstat.d

DTrace Toolkit には tcpstat.d という TCP の送受信量をカウントするスクリプトが入っています。

 # ./tcpstat.d    
     TCP_out   TCP_outRe      TCP_in   TCP_inDup    TCP_inUn
           0           0           0           0           0
         122           0           0           0           0
          61           0           0           0           0
          61           0           0           0           0
      314670           0      314609           0           0
      159488           0      159427           0           0
       31213           0       31152           0           0
 ...

ndd -get /dev/tcp

"ndd -get /dev/tcp \\?" を実行すると TCP のパラメータの一部を表示する事が出来ます。

 # ndd -get /dev/tcp \\?
 ?                             (read only)
 tcp_time_wait_interval        (read and write)
 tcp_conn_req_max_q            (read and write)
 tcp_conn_req_max_q0           (read and write)
 tcp_conn_req_min              (read and write)
 tcp_conn_grace_period         (read and write)
 tcp_cwnd_max                  (read and write)
 tcp_debug                     (read and write)
 tcp_smallest_nonpriv_port     (read and write)
 ...

パラメータ名を指定するとパラメータの値を取得する事が出来ます。"(read and write)" なパラメータに関しては -set を指定すると値を設定する事が出来ます。

 # ndd -get /dev/tcp tcp_time_wait_interval
 60000

IP の統計情報を見る

netstat -sP ip 1

"netstat -sP ip 1" を実行すると IP の統計情報を表示する事が出来ます。

 % netstat -sP ip 1
 ...
 IPv4    ipForwarding        =     2     ipDefaultTTL        =   255
         ipInReceives        =     2     ipInHdrErrors       =     0
         ipInAddrErrors      =     0     ipInCksumErrs       =     0
         ipForwDatagrams     =     0     ipForwProhibits     =     0
         ipInUnknownProtos   =     0     ipInDiscards        =     0
         ipInDelivers        =     2     ipOutRequests       =     2
         ipOutDiscards       =     0     ipOutNoRoutes       =     0
         ipReasmTimeout      =     0     ipReasmReqds        =     0
         ipReasmOKs          =     0     ipReasmFails        =     0
         ipReasmDuplicates   =     0     ipReasmPartDups     =     0
         ipFragOKs           =     0     ipFragFails         =     0
         ipFragCreates       =     0     ipRoutingDiscards   =     0
         tcpInErrs           =     0     udpNoPorts          =     0
         udpInCksumErrs      =     0     udpInOverflows      =     0
         rawipInOverflows    =     0     ipsecInSucceeded    =     0
         ipsecInFailed       =     0     ipInIPv6            =     0
         ipOutIPv6           =     0     ipOutSwitchIPv6     =     0
 ...

同様に ICMP や RAWIP の統計情報を表示させる事も可能です。

 % netstat -sP icmp 1
 ICMPv4  icmpInMsgs          =     0     icmpInErrors        =     0
         icmpInCksumErrs     =     0     icmpInUnknowns      =     0
         icmpInDestUnreachs  =     0     icmpInTimeExcds     =     0
         icmpInParmProbs     =     0     icmpInSrcQuenchs    =     0
         icmpInRedirects     =     0     icmpInBadRedirects  =     0
         icmpInEchos         =     0     icmpInEchoReps      =     0
         icmpInTimestamps    =     0     icmpInTimestampReps =     0
         icmpInAddrMasks     =     0     icmpInAddrMaskReps  =     0
         icmpInFragNeeded    =     0     icmpOutMsgs         =     0
         icmpOutDrops        =     0     icmpOutErrors       =     0
         icmpOutDestUnreachs =     0     icmpOutTimeExcds    =     0
         icmpOutParmProbs    =     0     icmpOutSrcQuenchs   =     0
         icmpOutRedirects    =     0     icmpOutEchos        =     0
         icmpOutEchoReps     =     0     icmpOutTimestamps   =     0
         icmpOutTimestampReps=     0     icmpOutAddrMasks    =     0
         icmpOutAddrMaskReps =     0     icmpOutFragNeeded   =     0
         icmpInOverflows     =     0

kstat -p 'ip:::' 1

"kstat -p 'ip:::' 1" を実行すると、カーネル内に保存されている IP に関する統計情報を出力する事が出来ます。これが "netstat -sP ip 1" の出力の元データです。

 % kstat -p 'ip:::' 1
 ...
 ip:0:ip:inDelivers      4629963
 ip:0:ip:inDiscards      0
 ip:0:ip:inErrs  0
 ip:0:ip:inHdrErrors     0
 ip:0:ip:inIPv6  0
 ip:0:ip:inReceives      4862389
 ip:0:ip:inUnknownProtos 21643
 ...

ndd -get /dev/ip

"ndd -get /dev/ip \\?" を実行すると IP のパラメータの一部を取得する事が出来ます。

 # ndd -get /dev/ip \\?
 ?                             (read only)
 ip_respond_to_address_mask_broadcast(read and write)
 ip_respond_to_echo_broadcast  (read and write)
 ip_respond_to_echo_multicast  (read and write)
 ip_respond_to_timestamp       (read and write)
 ip_respond_to_timestamp_broadcast(read and write)
 ip_send_redirects             (read and write)

パラメータ名を指定すると値を取得する事が出来ます。"(read and write)" と表示されているパラメータは -set オプションで値を設定する事も可能です。

 # ndd -get /dev/ip ip_lso_outbound
 1

どんなパケットが流れているかを調べる

snoop -d <NIC>

"snoop -d <NIC>" を実行すると、送受信したパケット毎に送信元 IP アドレス、宛先 IP アドレス、プロトコル、ポート番号等を調べる事が出来ます。他の OS の tcpdump に相当するコマンドです。"TELNET" と表示されているパケットは telnet のパケットです。-r オプションは名前解決をさせない為に付けていますが、必ずしも付ける必要はありません。snoop の実行はそれ自体がネットワークの負荷になりますので、必要な時にだけ使用して下さい。

 # snoop -r -d e1000g0 
 Using device /dev/e1000g0 (promiscuous mode)
 10.16.100.16 -> 10.16.67.5   TELNET C port=40383 
   10.16.67.5 -> 10.16.100.16 TELNET R port=40383 Using device /dev/e1
 10.16.100.16 -> 10.16.67.5   TELNET C port=40383 
  10.16.11.16 -> (broadcast)  ARP C Who is 10.16.0.200, 10.16.0.200 ?
   10.16.64.5 -> (broadcast)  ARP C Who is 10.16.201.102, 10.16.201.102 ?
            ? -> \*            ETHER Type=9000 (Loopback), size = 60 bytes

パケットサイズを調べる

snoop -d <NIC> -S

"snoop -d <NIC> -S" を実行すると length: に続いてパケットのサイズを出力させる事が可能です。パケットのサイズによってネットワークの負荷が変わってきます(一般にパケットが小さい方が負荷が高い)。

 # snoop -d e1000g0 -S
   10.16.98.12 -> (broadcast)  length:   60  ARP C Who is 10.16.38.2, 10.16.38.2 ?
             ? -> (multicast)  length:   52  ETHER Type=0000 (LLC/802.3), size = 52 bytes
    10.16.38.2 -> 10.255.255.255 length:  178  BPARAM C GETFILE root
    10.16.64.5 -> (broadcast)  length:   60  ARP C Who is 10.16.64.54, 10.16.64.54 ?
   10.16.98.16 -> (broadcast)  length:   60  ARP C Who is 10.16.38.2, 10.16.38.2 ?

詳しくパケットの中身を調べる

snoop -d <NIC> -V

"snoop -r -d <NIC> -V" を実行するとネットワークの階層毎に詳細な情報を出力させる事が出来ます。"________________________________" で挟まれている部分が一つのパケットです。"ETHER"、"IP"、"TCP"、"TELNET" と階層毎に一行出力されているのが分かります。

 # snoop -r -d e1000g0 -V
 Using device /dev/e1000g0 (promiscuous mode)
 ________________________________
 10.16.100.16 -> 10.16.67.5   ETHER Type=0800 (IP), size = 60 bytes
 10.16.100.16 -> 10.16.67.5   IP  D=10.16.67.5 S=10.16.100.16 LEN=40, ID=44170, TOS=0x0, TTL=64
 10.16.100.16 -> 10.16.67.5   TCP D=23 S=40383 Ack=2979015144 Seq=1218855275 Len=0 Win=49640
 10.16.100.16 -> 10.16.67.5   TELNET C port=40383 
 ________________________________
   10.16.67.5 -> 10.16.100.16 ETHER Type=0800 (IP), size = 100 bytes
   10.16.67.5 -> 10.16.100.16 IP  D=10.16.100.16 S=10.16.67.5 LEN=86, ID=8412, TOS=0x0, TTL=60
   10.16.67.5 -> 10.16.100.16 TCP D=40383 S=23 Push Ack=1218855275 Seq=2979015144 Len=46 Win=49640
   10.16.67.5 -> 10.16.100.16 TELNET R port=40383 Using device /dev/e1
 ________________________________

snoop -d <NIC> -v

"snoop -d <NIC> -v" を実行すると更に詳しくパケットの中身を調べる事が出来ます。各ヘッダの中身とペイロードの中身が可能な限り分かりやすく整形されて出力されます。

 # snoop -d <NIC> -v
 ...
 ETHER:  ----- Ether Header -----
 ETHER:  
 ETHER:  Packet 2999 arrived at 17:59:25.31440
 ETHER:  Packet size = 91 bytes
 ETHER:  Destination = 0:3:ba:37:34:a8, 
 ETHER:  Source      = 0:23:8b:64:88:60, 
 ETHER:  Ethertype = 0800 (IP)
 ETHER:  
 IP:   ----- IP Header -----
 IP:   
 IP:   Version = 4
 IP:   Header length = 20 bytes
 IP:   Type of service = 0x00
 IP:         xxx. .... = 0 (precedence)
 IP:         ...0 .... = normal delay
 IP:         .... 0... = normal throughput
 IP:         .... .0.. = normal reliability
 IP:         .... ..0. = not ECN capable transport
 IP:         .... ...0 = no ECN congestion experienced
 IP:   Total length = 77 bytes
 IP:   Identification = 18244
 IP:   Flags = 0x4
 IP:         .1.. .... = do not fragment
 IP:         ..0. .... = last fragment
 IP:   Fragment offset = 0 bytes
 IP:   Time to live = 60 seconds/hops
 IP:   Protocol = 6 (TCP)
 IP:   Header checksum = 0000
 IP:   Source address = 10.16.67.5, 10.16.67.5
 IP:   Destination address = 10.16.100.16, 10.16.100.16
 IP:   No options
 IP:   
 TCP:  ----- TCP Header -----
 TCP:  
 TCP:  Source port = 23
 TCP:  Destination port = 40383 
 TCP:  Sequence number = 2990317620
 TCP:  Acknowledgement number = 1218855394
 TCP:  Data offset = 20 bytes
 TCP:  Flags = 0x18
 TCP:        0... .... = No ECN congestion window reduced
 TCP:        .0.. .... = No ECN echo
 TCP:        ..0. .... = No urgent pointer
 TCP:        ...1 .... = Acknowledgement
 TCP:        .... 1... = Push
 TCP:        .... .0.. = No reset
 TCP:        .... ..0. = No Syn
 TCP:        .... ...0 = No Fin
 TCP:  Window = 49640
 TCP:  Checksum = 0xbb74
 TCP:  Urgent pointer = 0
 TCP:  No options
 TCP:  
 TELNET:  ----- TELNET:   -----
 TELNET:  
 TELNET:  "IP:   ----- IP Header -----\\r\\nIP:   \\r\\n"
 TELNET:  
 ...

snoop -d <NIC> -x <OFFSET>

"snoop -d <NIC> -x <OFFSET>" を実行すると、パケットの中身をダンプする事が出来ます。通信の内容を調査したい時に使用して下さい。<OFFSET> をゼロにするとパケットのヘッダも含めて全てのデータをダンプする事が出来ます。以下は telnet ポートの通信をペイロードのみ表示させた例です。telnet で接続した状態で id コマンドを を発行して "uid=0(root) gid=0(root)" の出力を得ています。

 # snoop -r -d e1000g0 -x 54 port 23 
 Using device /dev/e1000g0 (promiscuous mode)
 10.16.100.16 -> 10.16.67.5   TELNET C port=40386 i
 
            0: 6900 0000 0000                             i.....
 
   10.16.67.5 -> 10.16.100.16 TELNET R port=40386 i
 
            0: 69                                         i
 
 10.16.100.16 -> 10.16.67.5   TELNET C port=40386 
 
            0: 0000 0000 0000                             ......
 
 10.16.100.16 -> 10.16.67.5   TELNET C port=40386 d
 
            0: 6400 0000 0000                             d.....
 
   10.16.67.5 -> 10.16.100.16 TELNET R port=40386 d
 
            0: 64                                         d
 
 10.16.100.16 -> 10.16.67.5   TELNET C port=40386 
 
            0: 0000 0000 0000                             ......
 
 10.16.100.16 -> 10.16.67.5   TELNET C port=40386 
 
            0: 0d00 0000 0000                             ......
 
   10.16.67.5 -> 10.16.100.16 TELNET R port=40386 
 
            0: 0d0a                                       ..
 
 10.16.100.16 -> 10.16.67.5   TELNET C port=40386 
 
            0: 0000 0000 0000                             ......
 
   10.16.67.5 -> 10.16.100.16 TELNET R port=40386 uid=0(root) gid=0(ro
 
            0: 7569 643d 3028 726f 6f74 2920 6769 643d    uid=0(root) gid=
           16: 3028 726f 6f74 290d 0a23 20                0(root)..# 
 
 10.16.100.16 -> 10.16.67.5   TELNET C port=40386 
 
            0: 0000 0000 0000                             ......

パケットをファイルにダンプする

snoop -o <FILE> -d <NIC>

"snoop -o <FILE> -d <NIC> を実行すると送受信したパケットを全てファイルに保存する事が出来ます。通信の内容を一旦ファイルに保存して後でゆっくり解析する事が出来るので非常に便利です。通信量に応じてファイルのサイズも大きくなりますので、ご注意下さい。

 # snoop -o /var/tmp/snoop01.dump -d e1000g0
 Using device /dev/e1000g0 (promiscuous mode)
 24 \^C

保存したファイルは "snoop -i <FILE>" で読み込む事が出来ます。今までご紹介した snoop のオプションも合わせて使用する事が出来ます。

 # snoop -r -i /var/tmp/snoop01.dump -V | head
 ________________________________
   1   0.00000 10.16.100.16 -> 10.16.67.5   ETHER Type=0800 (IP), size = 60 bytes
   1   0.00000 10.16.100.16 -> 10.16.67.5   IP  D=10.16.67.5 S=10.16.100.16 LEN=40, ID=21844, TOS=0x0, TTL=64
   1   0.00000 10.16.100.16 -> 10.16.67.5   TCP D=23 S=40383 Ack=3027145344 Seq=1218855542 Len=0 Win=49640
   1   0.00000 10.16.100.16 -> 10.16.67.5   TELNET C port=40383 
 ________________________________
   2   0.00001   10.16.67.5 -> 10.16.100.16 ETHER Type=0800 (IP), size = 104 bytes
   2   0.00001   10.16.67.5 -> 10.16.100.16 IP  D=10.16.100.16 S=10.16.67.5 LEN=90, ID=28393, TOS=0x0, TTL=60
   2   0.00001   10.16.67.5 -> 10.16.100.16 TCP D=40383 S=23 Push Ack=1218855542 Seq=3027145344 Len=50 Win=49640
   2   0.00001   10.16.67.5 -> 10.16.100.16 TELNET R port=40383 Using device /dev

別のホストに到達可能かを調べる

ping <HOST>

"ping <HOST>" を実行すると、指定したホストまで到達可能か確認する事が出来ます。

 # ping 10.16.62.7   
 10.16.62.7 is alive

"ping -s <HOST>" を実行すると、定期的に ping を打つ事が出来ます。

 # ping -s 10.16.62.7
 PING 10.16.62.7: 56 data bytes
 64 bytes from 10.16.62.7: icmp_seq=0. time=0.872 ms
 64 bytes from 10.16.62.7: icmp_seq=1. time=0.280 ms
 64 bytes from 10.16.62.7: icmp_seq=2. time=0.214 ms
 \^C
 ----10.16.62.7 PING Statistics----
 3 packets transmitted, 3 packets received, 0% packet loss
 round-trip (ms)  min/avg/max/stddev = 0.214/0.455/0.872/0.36

ブロードキャストアドレス宛に ping を打つと同じセグメントに居るマシンを調べる事が出来ます。

 # ping -s 10.16.255.255
 PING 10.16.255.255: 56 data bytes
 64 bytes from sanuki05.jp.iforce.net (10.16.67.5): icmp_seq=0. time=0.0850 ms
 64 bytes from 10.16.11.15: icmp_seq=0. time=0.325 ms
 64 bytes from 10.16.65.51: icmp_seq=0. time=0.485 ms
 64 bytes from 10.16.11.13: icmp_seq=0. time=0.581 ms
 64 bytes from 10.16.62.65: icmp_seq=0. time=0.666 ms
 ...

ルーティングテーブルを表示する

netstat -nr

"netstat -r" を実行するとルーティングテーブルを表示する事が出来ます。"default" の行がデフォルトゲートウェイです。経路情報が正しくないと宛先のホストに到達する事が出来ません。

 # netstat -nr
 
 Routing Table: IPv4
   Destination           Gateway           Flags  Ref     Use     Interface 
 -------------------- -------------------- ----- ----- ---------- --------- 
 default              10.16.0.254          UG        1       1054           
 10.16.0.0            10.16.67.5           U         1        202 e1000g0   
 224.0.0.0            10.16.67.5           U         1          0 e1000g0   
 127.0.0.1            127.0.0.1            UH        4         77 lo0

"route -f" を実行するとルーティングテーブルを最新の状態に更新する事が出来ます。

 # route -f

宛先ホストまでの経路を調べる

traceroute <HOSTNAME>

"traceroute <HOSTNAME>" を実行すると、宛先ホストまでの経路を調べる事が出来ます。

 # traceroute 10.16.0.254
 traceroute to 10.16.0.254 (10.16.0.254), 30 hops max, 40 byte packets
  1  10.16.100.254 (10.16.100.254)  0.474 ms \*  0.493 ms

プロセスが開いているソケットを調べる

pfiles <PID>

"pfiles <PID>" を実行すると、プロセスが開いているファイルとソケットを調べる事が出来ます。以下の例では sshd プロセスがポート 22 番を開いている事が分かります。どのホスト宛にどんなオプションで幾つのセッションを張っているのかを把握する事はネットワークの解析に役立ちます。

 # pfiles 570
 570:    /usr/lib/ssh/sshd
   Current rlimit: 256 file descriptors
    0: S_IFCHR mode:0666 dev:284,0 ino:6815752 uid:0 gid:3 rdev:13,2
       O_RDWR|O_LARGEFILE
       /devices/pseudo/mm@0:null
    1: S_IFCHR mode:0666 dev:284,0 ino:6815752 uid:0 gid:3 rdev:13,2
       O_RDWR|O_LARGEFILE
       /devices/pseudo/mm@0:null
    2: S_IFCHR mode:0666 dev:284,0 ino:6815752 uid:0 gid:3 rdev:13,2
       O_RDWR|O_LARGEFILE
       /devices/pseudo/mm@0:null
    3: S_IFSOCK mode:0666 dev:291,0 ino:50619 uid:0 gid:0 size:0
       O_RDWR|O_NONBLOCK
         SOCK_STREAM
         SO_REUSEADDR,SO_SNDBUF(49152),SO_RCVBUF(49152),IP_NEXTHOP(0.192.0.0)
         sockname: AF_INET6 ::  port: 22
    7: S_IFREG mode:0666 dev:285,1 ino:65539 uid:0 gid:0 size:0
       O_RDWR|O_LARGEFILE
       /system/contract/process/template

以下のコマンドを実行すると全てのプロセスが開いているソケットをプロセス毎に調べる事が出来ます。

 # ps -eo pid,fname | grep -v PID | while read pid fname; do echo ${fname}; pfiles ${pid} | egrep 'peername|sockname' ; done

プロセスが発行したシステムコールを監視する

truss -cp <PID>

"truss -cp <PID>" を実行するとプロセスが発行したシステムコールとその回数を調べる事が出来ます。ネットワークの送受信もシステムコールを利用しています。例えば以下の例は sshd をトレースした物ですが、read, write, shutdown 等はネットワークのトラフィックに使用されたシステムコールです。システムコールの種類や回数は性能に大きく影響します。予想したよりもスループットが出ていない場合は、このコマンドを試してみて下さい。なお、<PID> に指定するプロセス ID は pgrep コマンドで渡す事も可能です。

 # truss -cp `pgrep -xn sshd` 
 signals ------------
 SIGCLD             1
 total:             1
 
 
 syscall               seconds   calls  errors
 _exit                    .000       1
 read                     .185    9804       1
 write                    .152    9641
 close                    .000       4
 chmod                    .000       1
 chown                    .000       1
 brk                      .000       2
 getuid                   .000       1
 sigaction                .000       1
 setcontext               .000       1
 waitid                   .000       2       1
 lwp_sigmask              .128   19433
 pollsys                  .081    9717
 stat64                   .000       1
 shutdown                 .000       1
                      --------  ------   ----
 sys totals:              .549   48611      2
 usr time:                .256
 elapsed:                5.690

truss -vall -E -p <PID>

"truss -vall -E -p <PID>" を実行するとプロセスが発行しているシステムコールを逐次表示する事が出来ます。システムコールに消費した時間、引数、返り値等も合わせて調べる事が出来るので、ネットワークの解析にも非常に有効です。snoop コマンドではパケットレベルでの通信内容を見る事が出来ましたが、truss を使用するとアプリケーションレベルで通信内容を調べる事が出来ます。以下の例では telnet で "ls" と入力しています。

 # truss -vall -E -p `pgrep -xn telnet`
 pollsys(0x08047670, 2, 0x00000000, 0x00000000) (sleeping...)
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=POLLOUT
  0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=POLLRDNORM
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=0
  0.0000 read(0, " l", 1024)                             = 1
  0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLOUT|POLLRDNORM|POLLRDBAND rev=POLLOUT
         timeout: 0.000000000 sec
  0.0000 send(4, " l", 1, 0)                             = 1
  0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000)  = 0
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=0
         timeout: 0.000000000 sec
  0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=POLLRDNORM
  0.0000 recv(4, " l", 1024, 0)                          = 1
  0.0000 pollsys(0x08047670, 3, 0x08047748, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=0
         fd=1  ev=POLLOUT rev=POLLOUT
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=0
         timeout: 0.000000000 sec
  0.0000 write(1, " l", 1)                               = 1
  0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=POLLRDNORM
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=0
  0.0000 read(0, " s", 1024)                             = 1
  0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLOUT|POLLRDNORM|POLLRDBAND rev=POLLOUT
         timeout: 0.000000000 sec
  0.0000 send(4, " s", 1, 0)                             = 1
  0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000)  = 0
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=0
         timeout: 0.000000000 sec
  0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=POLLRDNORM
  0.0000 recv(4, " s", 1024, 0)                          = 1
  0.0000 pollsys(0x08047670, 3, 0x08047748, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=0
         fd=1  ev=POLLOUT rev=POLLOUT
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=0
         timeout: 0.000000000 sec
  0.0000 write(1, " s", 1)                               = 1
  0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=POLLRDNORM
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=0
  0.0000 read(0, "\\r", 1024)                             = 1
  0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLOUT|POLLRDNORM|POLLRDBAND rev=POLLOUT
         timeout: 0.000000000 sec

truss -o <FILE> -vall -E -p <PID>

truss も snoop と同様にファイルにダンプする事が可能です。

 # truss -o /var/tmp/truss01.dump -vall -E -p `pgrep -xn telnet`

ダンプしたファイルはテキストファイルです。

 # head /var/tmp/truss01.dump
 pollsys(0x08047670, 2, 0x00000000, 0x00000000) (sleeping...)
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=POLLOUT
  0.0000 pollsys(0x08047670, 2, 0x00000000, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=POLLRDNORM
         fd=4  ev=POLLRDNORM|POLLRDBAND rev=0
  0.0000 read(0, " l", 1024)                             = 1
  0.0000 pollsys(0x08047670, 2, 0x08047748, 0x00000000)  = 1
         fd=0  ev=POLLRDNORM rev=0
         fd=4  ev=POLLOUT|POLLRDNORM|POLLRDBAND rev=POLLOUT

プロセス毎にトラフィックを監視する

tcpwdist.d

DTrace Toolkit には tcpwdist.d というプロセス毎に TCP の送受信サイズの分布を調査するスクリプトが入っています。

 # ./tcpwdist.d 
 Tracing... Hit Ctrl-C to end.
 \^C
  PID: 0      CMD: sched\\0
 
            value  ------------- Distribution ------------- count    
                1 |                                         0        
                2 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1        
                4 |                                         0        
 
  PID: 19299  CMD: /usr/sbin/dtrace -s ./tcpwdist.d\\0
 
            value  ------------- Distribution ------------- count    
                8 |                                         0        
               16 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 1        
               32 |                                         0        
 
  PID: 19246  CMD: telnet 10.16.100.16\\0
 
            value  ------------- Distribution ------------- count    
                0 |                                         0        
                1 |@                                        13       
                2 |                                         3        
                4 |                                         3        
                8 |                                         1        
               16 |                                         6        
               32 |@                                        12       
               64 |@                                        22       
              128 |@                                        15       
              256 |@@@@@@@@@@@@@@@@                         258      
              512 |@@                                       28       
             1024 |@@@@@@@@@@@@@@@@@@                       286      
             2048 |                                         0        

おわりに

以上 Solaris のネットワーク解析ツールの内、基本的な物をご紹介しました。状況に応じて各コマンドを使い分け、問題解決にお役立て下さい。DTrace や kstat を使用すると、更に詳細な分析を行う事も可能です。是非ご活用下さい。

投稿されたコメント:

コメント
コメントは無効になっています。
About

Search

Archives
« 6月 2016
   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
  
       
今日