X

Oracle Solaris, Oarcle ハードウェア製品に関する情報

  • Sun
    April 19, 2009

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

Guest Author


はじめに

今回は 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 を使用すると、更に詳細な分析を行う事も可能です。是非ご活用下さい。

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.