やっぱり Sun がスキ! : Weblog やっぱり Sun がスキ!

やっぱり Sun がスキ!

http://blogs.sun.com/yappri/date/20090424 2009年 4月 24日 金曜日

Sunグッズ紹介(21) なにがあってもやっぱり Sun Goods もスキ!

Sun のロゴ入りグッズ紹介の第二十一弾です。

Sun Goods コレクターとして日々グッズ収集に勤しんでいたら 個人持ちのグッズが大変な量になってしまいました。

整理整頓する機会があったので一部公開してみます。 写真並べまくっただけですがご容赦を。 是非、懐かしんだり・驚いたりしてください。 (画像をクリックすると拡大出来ます)


・duke
duke.jpg


・ストラップ
strap.jpg


・ネックストラップ
strap2.jpg


・バッチ
budge.jpg


・鞄
bag.jpg


・ぬいぐるみ
toy.jpg


・帽子
cap.jpg


・服
shirt.jpg


・ペン
pen.jpg


・付箋紙
sticky.jpg


・その他いろいろ
other.jpg

http://blogs.sun.com/yappri/date/20090423 2009年 4月 23日 木曜日

X4270 の prtdiag 解説

先日、サンは Intel Xeon 5500 番台 CPU を搭載したサーバ群を 発表しましたが、今回この CPU を搭載した Sun Fire X4270 の prtdiag コマンドの出力結果を取得しましたので、アーキテクチャの解説と併せて 解説してみます。


       Sun Fire X4270



まずは、 prtdiag -v の結果をご覧下さい。

# prtdiag -v
System Configuration: SUN MICROSYSTEMS SUN FIRE X4170/X4270/X4275 SERV
BIOS Configuration: American Megatrends Inc. 07013853 02/26/2009
BMC Configuration: IPMI 1.5 (KCS: Keyboard Controller Style)

==== Processor Sockets ====================================

Version                          Location Tag
-------------------------------- --------------------------
Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz CPU 1
Intel(R) Xeon(R) CPU           L5520  @ 2.27GHz CPU 2

==== Memory Device Sockets ================================

Type    Status Set Device Locator      Bank Locator
------- ------ --- ------------------- --------------------
other   in use 0   D2                  BANK2
other   empty  0   D1                  BANK1
other   empty  0   D0                  BANK0
other   in use 0   D5                  BANK5
other   empty  0   D4                  BANK4
other   empty  0   D3                  BANK3
other   in use 0   D8                  BANK8
other   empty  0   D7                  BANK7
other   empty  0   D6                  BANK6
other   in use 0   D2                  BANK2
other   empty  0   D1                  BANK1
other   empty  0   D0                  BANK0
other   in use 0   D5                  BANK5
other   empty  0   D4                  BANK4
other   empty  0   D3                  BANK3
other   in use 0   D8                  BANK8
other   empty  0   D7                  BANK7
other   empty  0   D6                  BANK6
FLASH   in use 0

==== On-Board Devices =====================================
 Zoar 2x GbE.
 Zoar 2x GbE.
 Zoar 2x GbE.
 Zoar 2x GbE.

==== Upgradeable Slots ====================================

ID  Status    Type             Description
--- --------- ---------------- ----------------------------
0   in use    PCI Express      PCIE0
1   available PCI Express      PCIE1
2   available PCI Express      PCIE2
3   available PCI Express      PCIE3
4   in use    PCI Express      PCIE4
5   available PCI Express      PCIE5


まず、 Processor Sockets の情報から、このサーバに搭載されている CPU の種類とソケット数が確認できます。
Ultra SPATC T シリーズの prtdiag では、スレッド単位で表示(例えば T5120 では 64 CPU) されますが、Sun Fire X4270 では、 CPU ソケット単位で表示されます。

mpstat で OS が認識しているスレッド数を確認すると、Intel Xeon 5500 番台 CPU は、4 Core で かつ Hyper-Threading を実装していますので、合計 16( 4 core x 2 Thread x 2 CPU) スレッドとなります。
# mpstat
CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
  0  249   0   73   383  159   73    0    4   53    0   335    0   1   0  99
  1   89   0   49    28    0   63    0    3   40    0   211    0   0   0 100
  2   62   0   44    43   15   64    0    2   38    0   170    0   0   0 100
  3   70   0   44    32    4   62    0    2   36    0   155    0   0   0 100
  4  275   0   84    29    4   57    0    3   49    0   384    0   0   0  99
  5   91   0   36    37    9   25    0    2   35    0   146    0   0   0 100
  6   52   0   25    29    0   21    0    1   29    0   139    0   0   0 100
  7   64   0   27    29    0   20    0    1   29    0   123    0   0   0 100
  8   58   0   16    30    0   41    0    1   31    0    89    0   0   0 100
  9   33   0    8    30    0   35    0    1   28    0    43    0   0   0 100
 10   24   0    5    30    0   32    0    1   28    0    32    0   0   0 100
 11   21   0    4    30    0   44    0    1   27    0    27    0   0   0 100
 12   52   0   12    30    0    7    0    1   26    0    62    0   0   0 100
 13   30   0    6    30    0    6    0    1   25    0    34    0   0   0 100
 14   21   0    3    30    0    4    0    1   25    0    22    0   0   0 100
 15   21   0    3    30    0    4    0    1   25    0    22    0   0   0 100

Memory Device Sockets 関して、Intel Xeon 5500 番台 CPU は、DDR3 メモリを採用 し、CPU 毎に 3 メモリチャンネルあります。Sun Fire X4270 では、各チャンネ ル毎に 3 バンクの実装なので、メモリスロットは合計 18 ( 3 Channel x 3 BANK x 2 CPU) スロットになります。(ちなみに Sun Fire X4250 では 16 スロットでした。)


On-Board ネットワークに関して、ネットワークコントローラは Intel の Zoar(Intel 82575EB Gigabit Ethernet Controller) を 2 個搭載しています。各 Zoar 毎にネットワークのポートが 2 つありますので、合計で Gigabit Ethernet を 4 ポート搭載しています。
dladm で確認すると、 4 ポート表示され、ネットワークドライバは e1000g でなく igb である事が確認できます。
# dladm show-dev
igb0            link: up        speed: 1000  Mbps       duplex: full
igb1            link: unknown   speed: 0     Mbps       duplex: half
igb2            link: unknown   speed: 0     Mbps       duplex: half
igb3            link: unknown   speed: 0     Mbps       duplex: half

最後に、拡張 PCI Express スロットに関して、Sun Fire X4270 は PCIe2 を採用しており、 合計で 6 スロットあるのが確認できます。

今回は、prtdiag の結果から Intel Xeon 5500 番台 CPU 搭載サーバ Sun Fire X4270 の アーキテクチャを解説しました。今後新しいアーキテクチャのサーバが発表された時は また prtdiag の紹介をしたいと思います。


(参考情報)
過去の 「やっぱり Sun がスキ!」blog 記事一覧はこちらを参照下さい。 http://wikis.sun.com/display/yappri/Home


http://blogs.sun.com/yappri/date/20090422 2009年 4月 22日 水曜日

SJSMS - Solaris 10 の SMF に登録しよう

今回は久しぶり(なんと半年振り!)に Messaging Server ネタです。
以前のブログ記事(その 1,その 2)でインストールしてみた Messaging Server 関連コンポーネントを Solaris 10 の SMF に登録して、自動起動の設定をしてみましょう。
前回インストールした関連コンポーネントは以下の通りです。

  • Directory Server 6.3
  • Messaging Server 7.0
  • Application Server 9.1
    • Access Manager 7.1
    • Delegated Administrator 6.4
    • Sun Convergence 1.0

上記コンポーネントの中で、Access Manager, Delegated Administrator, Sun Convergence は、Application Server 9.1 上に配備されておりますので、SMF に登録して自動起動の設定をする必要があるコンポーネントは以下 の 3 つになります。

  • Directory Server 6.3
  • Messaging Server 7.0
  • Application Server 9.1

では、順番に、SMF に登録していきましょう。

目次

  1. Directory Server 6.3 を SMF に登録
  2. Messaging Server 7.0 を SMF に登録
  3. Application Server 9.1 を SMF に登録
  4. 参考情報

Directory Server 6.3 を SMF に登録

実は、Directory Server 6.3 の提供方法は、パッケージ版と ZIP アーカイブ版の 2 種類があり、 インストール・設定に若干の差異があります。
パッケージ版の Directory Server では、dsadm コマンドから SMF にサービスを登録する方法が あるのですが、ZIP アーカイブ版では、dsadm コマンドから SMF にサービスを登録する事が出来ません。
  ※ パッケージ版のためのご参考
以前のブログ記事で紹介したインストール手順では、ZIP アーカイブ版の Directory Server を 使用しているので、dsadm enable-service コマンドが使えません。
そこで今回は、/opt/SUNWdsee/ds6/install 配下に用意されているテンプレートファイルを 使って、SMF に登録します。

 sw-89# pwd
 /opt/SUNWdsee/ds6/install
 sw-89# cp tmpl_smf.manifest ds6_for_ms7_smf.manifest
  ※ あらかじめ、template ファイルをコピーします。
 sw-89# vi ds6_for_ms7_smf.manifest
  ※ manifest ファイルを下記 diff に示される様に編集します。
  ※ 具体的には、"%%%DATE_CREATED%%%", "%%%INSTALL_PATH%%%"
  ※ "%{sunds/path}", "%%%TIMEOUT_SECONDS%%%" を適宜編集します。
 sw-89# diff ds6_for_ms7_smf.manifest tmpl_smf.manifest
 6c6
 <     Created on : 2009/04/16
 ---
 >     Created on : %%%DATE_CREATED%%%
 24,25c24,25
 <                  exec="/opt/SUNWdsee/ds6/bin/dsadm start --exec /var/opt/SUNWdsee/dsins1"
 <                  timeout_seconds="600">
 ---
 >                  exec="%%%INSTALL_PATH%%%/bin/dsadm start --exec %{sunds/path}"
 >                  timeout_seconds="%%%TIMEOUT_SECONDS%%%">
 35,36c35,36
 <                  exec="/opt/SUNWdsee/ds6/bin/dsadm stop --exec /var/opt/SUNWdsee/dsins1"
 <                  timeout_seconds="600">
 ---
 >                  exec="%%%INSTALL_PATH%%%/bin/dsadm stop --exec %{sunds/path}"
 >                  timeout_seconds="%%%TIMEOUT_SECONDS%%%">
 sw-89#
 
 sw-89# cat ds6_for_ms7_smf.manifest
 <?xml version='1.0'?>
 <!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>

 <!--
     Document   : ds6-service.xml
     Created on : 2009/04/16
     Author     : Directory Server Enterprise Edition Team
     Description: The SMF Service Manifest file for Directory Server 6
 -->

 <service_bundle type="manifest"
                 name="SUNWldap-directory services">
   <service name="application/sun/ds" type="service" version="1">
     <dependency name="filesystems" grouping="require_all"
               restart_on="none" type="service">
       <service_fmri value="svc:/system/filesystem/local:default"/>
     </dependency>
     <dependency name="network" grouping="require_all"
              restart_on="none" type="service">
       <service_fmri value="svc:/network/initial:default"/>
     </dependency>
     <exec_method type="method"
                  name="start"
                  exec="/opt/SUNWdsee/ds6/bin/dsadm start --exec /var/opt/SUNWdsee/dsins1"
                  timeout_seconds="600">
       <method_context working_directory=":default">
         <method_credential user="root"
                            group=":default"
                            privileges=":default"/>
       </method_context>
       <stability value="Evolving"/>
     </exec_method>
     <exec_method type="method"
                  name="stop"
                  exec="/opt/SUNWdsee/ds6/bin/dsadm stop --exec /var/opt/SUNWdsee/dsins1"
                  timeout_seconds="600">
       <method_context working_directory=":default">
         <method_credential user="root"
                            group=":default"
                            privileges=":default"/>
       </method_context>
       <stability value="Evolving"/>
     </exec_method>
     <instance name="default" enabled="false"/>
     <stability value="Evolving"/>
     <template>
       <common_name>
         <loctext xml:lang="C"> Directory Server </loctext>
       </common_name>
       <documentation>
         <doc_link name="Directory Server Enterprise Edition 6 Administration Guide" uri="http://docs.sun.com/doc/819-0995/"/>
       </documentation>
     </template>
   </service>
 </service_bundle>
 sw-89#
 
 sw-89# svccfg import ./ds6_for_ms7_smf.manifest
  ※ 上記で作成した manifest ファイルを svccfg コマンドにて import します。
 
 sw-89# svcs ds
 STATE          STIME    FMRI
 disabled       14:52:43 svc:/application/sun/ds:default
  ※ svc:/application/sun/ds:default が追加されている事を確認します。
 
 sw-89# svcadm enable ds
  ※ svc:/application/sun/ds:default サービスをスタートします。
 
 sw-89# ps -ef | grep slapd
     root 13460  8891   0 14:54:59 ?           0:01 /opt/SUNWdsee/ds6/lib/64/ns-slapd -D /var/opt/SUNWdsee/dsins1 -i /var/opt/SUNWd
     root 13463  9868   0 14:55:01 pts/3       0:00 grep slapd
 sw-89# 
  ※ ns-slapd (Directory Server のプロセス) が起動している事が確認出来ます。
 
 sw-89# svcs ds
 STATE          STIME    FMRI
 online         14:55:02 svc:/application/sun/ds:default
 sw-89# 
  ※ svc:/application/sun/ds:default サービスも online になっている事が確認出来ます。
 
 sw-89# svcadm disable ds
  ※ svc:/application/sun/ds:default サービスを停止します。 
 
 sw-89# svcadm disable ds
 sw-89# svcs ds
 STATE          STIME    FMRI
 online*        14:57:23 svc:/application/sun/ds:default
 sw-89# svcs ds
 STATE          STIME    FMRI
 disabled       14:57:27 svc:/application/sun/ds:default
 sw-89# 
  ※ svc:/application/sun/ds:default サービスが停止された事が確認出来ます。
 
 sw-89# svcadm enable ds
 sw-89# svcs ds
 STATE          STIME    FMRI
 offline*       14:58:12 svc:/application/sun/ds:default
 sw-89# svcs ds
 STATE          STIME    FMRI
 online         14:58:19 svc:/application/sun/ds:default
 sw-89# 
  ※ 最後に svc:/application/sun/ds:default サービスを起動させておきます。

以上で、Directory Server の SMF の登録が完了しました。

Messaging Server 7.0 を SMF に登録

次に Messaging Server を SMF に登録しましょう。
Messaging Server の登録方法も Directory Server と同様テンプレートファイル を利用して SMF に登録します。

 sw-89# pwd
 /opt/sun/comms/messaging64/data/install
 sw-89# ls
 pab.ldif                   schema2ug_store.ldif       schema2usergroup.ldif.rej
 restofmessaging.xml        schema2usergroup.ldif      watcher.xml
 sw-89#

まずこの場所に messaging.xml ファイルが存在するか確認してください。
messaging.xml が存在する場合は下記の手順(messaging.xml の作成・msgexe の編集)を 省略してください。
  ※ 当初提供されていた restofmessaging.xml, watcher.xml を利用する方法では
  ※ ただしく動作しない問題が見つかっております。
  ※ その問題の回避のため、messaging.xml の作成・msgexe の編集を行ないます。

 sw-89# pwd
 /opt/sun/comms/messaging64/lib
 sw-89# cp msgexe msgexe.orig
  ※ SMF から利用する起動・停止スクリプトのバックアップを作成します。
 sw-89# vi msgexe
  ※ msgexe を下記に示される様に編集します。
  ※ 具体的には、start-msg, stop-msg の引数($2) を削除、
  ※ refresh 時のコマンドを refresh コマンドに変更します。
 sw-89# cat msgexe
 #!/sbin/sh

 ##  Copy/Rename this script to //lib/
 ##  Please change $REPOS to the location of your SVN Repo

 . /lib/svc/share/smf_include.sh

 parser() {
         PROPERTY=$1
         # VALUE=`svcprop -p ${PROPERTY} watcher`
         VALUE=`svcprop -p ${PROPERTY} messaging_server`
         if [ "${VALUE}" = "\"\"" ] ; then
                 VALUE=
         fi
         echo $VALUE
 }

         MESSAGING_BASE=`parser application/messaging_server_base`

         if [ -z "${MESSAGING_BASE}" ] ; then
                 exit $SMF_EXIT_ERR_CONFIG
         fi

 case $1 in

         'start')
                 # ${MESSAGING_BASE}/bin/start-msg $2
                 ${MESSAGING_BASE}/bin/start-msg
                 if [ $? -ne 0 ] ; then
                         exit $SMF_EXIT_ERR_FATAL
                 fi
                 exit $SMF_EXIT_OK
                 ;;
         'stop')
                 # ${MESSAGING_BASE}/bin/stop-msg $2
                 ${MESSAGING_BASE}/bin/stop-msg
                 if [ $? -ne 0 ] ; then
                         exit $SMF_EXIT_ERR_FATAL
                 fi
                 exit $SMF_EXIT_OK
                 ;;
         'refresh')
                 # ${MESSAGING_BASE}/bin/stop-msg        $2
                 # sleep 5
                 # ${MESSAGING_BASE}/bin/start-msg $2
                 ${MESSAGING_BASE}/bin/refresh
                 if [ $? -ne 0 ] ; then
                         exit $SMF_EXIT_ERR_FATAL
                 fi
                 exit $SMF_EXIT_OK
                 ;;
         *)
                 echo "Usage: $0 { start | stop | refresh }"
                 exit $SMF_EXIT_ERR_FATAL
                 ;;
                 esac
 sw-89# 
 sw-89# cd /opt/sun/comms/messaging64/data/install
 sw-89# cp restofmessaging.xml messaging.xml
  ※ restofmessaging.xml を messaging.xml にコピーします。
 sw-89# vi messaging.xml
  ※ messaging.xml ファイルを下記に示される様に編集します。
  ※ 具体的には、dependency name='watcher' 部分をコメントアウト、
  ※ dependency name='DirectoryServer' を追加します。
  ※ 尚、dependency name='DirectoryServer' は、Directory Server
  ※ を別サーバにインストールしている場合は、不要です。
 sw-89# cat messaging.xml
 <?xml version="1.0"?>
 <!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
 <!--
 Sun Java Enterprise System Messaging Server 7.0 ( Cascabel )
 -->
 
 <service_bundle type='manifest' name='messaging_server'>
 
         <service
             name='network/messaging_server'
             type='service'
             version='1'>
 
             <create_default_instance enabled='false' />
 
             <single_instance />
 
             <dependency
                 name='network-service'
                 grouping='require_all'
                 restart_on='none'
                 type='service'>
                 <service_fmri value='svc:/network/service' />
             </dependency>
 
             <dependency
                 name='fs-local'
                 grouping='require_all'
                 restart_on='none'
                 type='service'>
                 <service_fmri value='svc:/system/filesystem/local' />
             </dependency>
 
             <dependency
                 name='name-services'
                 grouping='require_all'
                 restart_on='refresh'
                 type='service'>
                 <service_fmri value='svc:/milestone/name-services' />
             </dependency>
 
             <dependency
                 name='identity'
                 grouping='optional_all'
                 restart_on='refresh'
                 type='service'>
                 <service_fmri value='svc:/system/identity:domain' />
             </dependency>
 <!--
             <dependency
                 name='watcher'
                 grouping='require_all'
                 restart_on='refresh'
                 type='service'>
                 <service_fmri value='svc:/network/watcher' />
             </dependency>
 -->
             <dependency
                 name='DirectoryServer'
                 grouping='require_all'
                 restart_on='refresh'
                 type='service'>
                 <service_fmri value='svc:/application/sun/ds:default' />
             </dependency>
 
             <exec_method
                 type='method'
                 name='start'
                 exec='/opt/sun/comms/messaging64/lib/msgexe start'
                 timeout_seconds='180' >
             </exec_method>
 
             <exec_method
                 type='method'
                 name='stop'
                 exec='/opt/sun/comms/messaging64/lib/msgexe stop'
                 timeout_seconds='180' >
             </exec_method>
 
             <exec_method
                 type='method'
                 name='refresh'
                 exec='/opt/sun/comms/messaging64/lib/msgexe refresh'
                 timeout_seconds='180' >
             </exec_method>
 
             <property_group name='application' type='framework'>
                     <propval name='messaging_server_base' type='astring'
                             value='/opt/sun/comms/messaging64' />
             </property_group>
 
             <property_group name='startd' type='framework'>
                 <propval name='ignore_error' type='astring'
                         value='core,signal' />
             </property_group>
 
             <stability value='Unstable' />
 
     </service>
 
 </service_bundle>
 sw-89#

messaging.xml ファイルがあった場合もここから先は実行してください。

 sw-89# svccfg import ./messaging.xml
  ※ messaging.xml ファイルが出来たら、svccfg コマンドにて import します。
 sw-89# svcs network/messaging_server
 STATE          STIME    FMRI
 disabled       15:12:37 svc:/network/messaging_server:default
 sw-89# 
  ※ svc:/network/messaging_server:default が追加されている事を確認します。
 
 sw-89# svcadm enable messaging_server
  ※ svc:/network/messaging_server:default サービスをスタートします。
 sw-89# svcs messaging_server
 STATE          STIME    FMRI
 offline*       15:23:08 svc:/network/messaging_server:default
 sw-89# svcs messaging_server
 STATE          STIME    FMRI
 online         15:23:16 svc:/network/messaging_server:default
 sw-89#
  ※ svc:/network/messaging_server:default サービスが online になっている事が確認出来ます。

以上で、Messaging Server の SMF の登録が完了しました。


Application Server 9.1 を SMF に登録

最後に Application Server を SMF に登録しましょう。
Application Server は、テンプレートファイルの利用では無く、asadmin コマンドにて SMF に 登録出来ます。

 sw-89# cat /.passwordfile
 AS_ADMIN_USER=admin
 AS_ADMIN_PASSWORD=<admin ユーザの実際のパスワードを記載して下さい。>
 AS_ADMIN_MASTERPASSWORD=<マスターパスワードを記載して下さい。>
 sw-89# 
  ※ 自動起動用の password ファイルを作成します。
 sw-89# /opt/SUNWappserver/bin/asadmin create-service --type das --passwordfile /.passwordfile /opt/SUNWappserver/domains/domain1
 サービスが正常に作成されました。詳細は次のとおりです:
 サービスの名前:application/SUNWappserver/domain1
 サービスのタイプ:Domain
 サービスの設定場所:/opt/SUNWappserver/domains
 システム上のマニフェストファイルの場所:/var/svc/manifest/application/SUNWappserver/domain1_opt_SUNWappserver_domains/Domain-service-smf.xml
 このサービスは svcadm コマンドを使用して有効にできます。
 コマンド create-service は正常に実行されました。
 sw-89# 
  ※ asadmin create-service コマンドにて、SMF に登録します。
 sw-89# svcs domain1
 STATE          STIME    FMRI
 disabled       15:50:17 svc:/application/SUNWappserver/domain1:default
 sw-89# 
  ※ svc:/application/SUNWappserver/domain1:default が登録されている事が確認出来ます。
 sw-89# svcadm enable domain1
  ※ svc:/application/SUNWappserver/domain1:default サービスを起動します。
 sw-89# svcs domain1
 STATE          STIME    FMRI
 offline*       15:50:38 svc:/application/SUNWappserver/domain1:default
 sw-89# svcs domain1
 STATE          STIME    FMRI
 offline*       15:50:38 svc:/application/SUNWappserver/domain1:default
 sw-89# svcs domain1
 STATE          STIME    FMRI
 online         15:52:34 svc:/application/SUNWappserver/domain1:default
 sw-89# 
  ※ svc:/application/SUNWappserver/domain1:default サービスが online になっている事が確認出来ます。

以上で、前回インストールした Messaging Server 関連コンポーネントが Solaris の SMF に登録され、OS 起動時に自動起動されるように設定されました。

 sw-89# svcs ds messaging_server domain1
 STATE          STIME    FMRI
 online         14:58:19 svc:/application/sun/ds:default
 online         15:23:16 svc:/network/messaging_server:default
 online         15:52:34 svc:/application/SUNWappserver/domain1:default
 sw-89#


参考情報

http://blogs.sun.com/yappri/date/20090421 2009年 4月 21日 火曜日

mpstat コマンドの読み方

はじめに

先日 Solaris の vmstat コマンドについての記事 を書きましたが、今回は mpstat コマンドについて解説したいと思います。最近は Linux にも mpstat コマンドがありますが、Solaris の mpstat とは出力内容や実装が大きく異なりますので注意が必要です。

mpstat について

CPU がボトルネックになっている可能性がある場合は mpstat を使用する事で CPU の使用状況を調べる事が出来ます。vmstat でも CPU の統計情報を見る事が可能ですが、mpstat ではプロセッサ毎の統計情報が見られるため、より細かな分析が可能です。

mpstat は vmstat と同様に kstat のデータを集計しています。mpstat のソースコードは以下の URL にあります。本体のソースコードは 500 行程度しかありません。

mpstat のお勧めのオプション

インターバルのみ

 % mpstat 1

オプションはインターバルのみ指定して下さい。より正確な負荷状況を見る為、長期間の性能監視の場合でもインターバルは 1 秒にする事をお勧めします。ログとして保存する場合も、今時のマシンであればファイルのサイズはそれ程気にしなくて良いと思います。

mpstat の出力例

mpstat の出力はヘッダに加えて CPU 毎に一行ずつ出力されます。4 CPU Machine の場合は毎回 5 行ずつ出力されます。

 # mpstat 1
 CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
   0  189  11  185    42   38   51    1   15    3    0   291    1   2   0  98
   1  166   9  193    22   17  191    1   16    5    0   256    1   4   0  96
   2  131  10  190    28   23   49    1   14    3    0   282    1   1   0  98
   3  119  10  207   257  154   54    1   15    5    0   230    1   2   0  97
 CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
   0    0   0    2    21   16    8    0    2    0    0     2    0   0   0 100
   1    0   0    2    19   13  121    0    5    0    0     0    0   5   0  95
   2    6   0    1    13    8    8    0    1    0    0    65    0   0   0 100
   3    0   0    1   223  120   12    0    5    0    0     1    0   0   0 100
 CPU minf mjf xcal  intr ithr  csw icsw migr smtx  srw syscl  usr sys  wt idl
   0    0   0    1     9    6    2    0    1    0    0     5    0   0   0 100
   1    0   0    7    10    6  121    0    1    0    0     0    0   0   0 100
   2    0   0    2    12    7    6    0    0    0    0    55    0   0   0 100
   3    0   0    2   218  115    6    0    3    0    0     0    0   3   0  97

各カラムの意味

CPU

CPU はプロセッサ番号です。

CPU の値は 0 から 517 まで(正確には _SC_CPUID_MAX の値まで)です。 0 番から順に p_online(2) で CPU が存在しているか確認し、もし存在していていたらその番号を表示しています。CPU の値は /usr/src/cmd/stat/common/acquire.c の acquire_cpus() 関数でセットされている cs_id から取られています。

_SC_CPUID_MAX は /usr/src/uts/common/sys/unistd.h で定義されています。

    211 #define	_SC_CPUID_MAX		517	/* maximum CPU id */

minf

minf はマイナーフォルトが発生した回数です。現在はアドレススペースフォルトが発生した回数がそのままマイナーフォルトの回数として計算されています。

minf の値は /usr/src/uts/common/vm/vm_as.c の as_fault() 関数の中の CPU_STATS_ADDQ(CPU, vm, as_fault, 1); で加算されています。

minf の値は kstat -p 'cpu::vm:as_fault' 1" でも取得出来ます。

mjf

mjf はメジャーフォルトが発生した回数です。メジャーフォルトはメモリページを読み込む際に物理 I/O が発生した物のことを言います。

mjf の値は /usr/src/uts/common/os/bio.c の pageio_setup() 関数の中で集計されています。ページング用のバッファを用意する際に、B_READ フラグが立っていて B_ASYNC フラグが立っていない場合に CPU_STATS_ADDQ(cpup, vm, maj_fault, 1); で maj_fault の値がインクリメントされます。この maj_fault が mpstat の mjf の値として使用されます。

mjf の値は "kstat -p 'cpu::vm:maj_fault' 1" でも取得出来ます。

xcal

xcal はプロセッサ間のクロスコールの回数です。

xcal の値は CPU 毎に異なるコードで、カーネル内の様々な箇所で更新されています。

sun4v アーキテクチャの環境では /usr/src/uts/sun4v/os/mach_cpu_states.c の send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1); と send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); で集計されています。

x86 環境では /usr/src/uts/i86pc/os/x_call.c の xc_capture_cpus() 関数や xc_common() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1); で集計されています。

sun4u 環境では CPU 毎に /usr/src/uts/sun4u/cpu/us3_cheetah.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); や CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids); 、/usr/src/uts/sun4u/cpu/us3_cheetahplus.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped);、CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids);、/usr/src/uts/sun4u/cpu/opl_olympus.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped); や CPU_STATS_ADDQ(CPU, sys, xcalls, ncpuids);、send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1);、/usr/src/uts/sun4u/cpu/us3_jalapeno.c の send_mondo_set() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, shipped);、/usr/src/uts/sun4u/cpu/spitfire.c の send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1);、/usr/src/uts/sun4u/cpu/us3_common.c の send_one_mondo() 関数の中の CPU_STATS_ADDQ(CPU, sys, xcalls, 1); 等で更新されています。

sun4 環境では /usr/src/uts/sun4/os/x_call.c の xc_some() 関数の中の SEND_MBOX_ONLY(xc_cpuset, func, arg1, arg2, lcx, XC_WAIT);(SEND_MBOX_ONLY は /usr/src/uts/sun4/sys/xc_impl.h で定義されています)で加算されています。

xcal の値は "kstat -p 'cpu::sys:xcalls' 1" でも取得出来ます。

intr

intr はインタラプトの回数です。PIL_MAX(=15) までのレベルのインタラプト回数の総計を数えています。PIL は Processor Interrupt Level の略です。

intr の値は /usr/src/uts/sun4/ml/interrupt.s の SERVE_INTR (SPARC) や /usr/src/uts/i86pc/os/intr.c の cpu_stats.sys.intr (x86) で加算した値を /usr/src/uts/common/os/cpu.c の中でインタラプトレベル毎に集計しています。

intr の値は "kstat -p 'cpu::sys:intr' 1" でも取得出来ます。

ithr

ithr はインタラプト処理用のスレッドで処理されるインタラプトの回数です。LOCK_LEVEL(=10) までのレベルのインタラプト回数の総計を数えています。

ithr の値は /usr/src/uts/sun4/ml/interrupt.s の SERVE_INTR (SPARC) や /usr/src/uts/i86pc/os/intr.c の cpu_stats.sys.intr (x86) で加算した値を /usr/src/uts/common/os/cpu.c の中でインタラプトレベル毎に集計しています。

ithr の値は "kstat -p 'cpu::sys:intrthread' 1" でも取得出来ます。

csw

csw はコンテキストスイッチの回数です。icsw と対比して、自発的なコンテキストスイッチとも呼ばれます。リソース待ち等で CPU を明け渡した回数です。

csw の値は /usr/src/uts/common/disp/disp.c の swtch() 関数や swtch_to() 関数の CPU_STATS_ADDQ(cp, sys, pswitch, 1);、swtch_from_zombie() 関数の CPU_STATS_ADDQ(CPU, sys, pswitch, 1); で加算されています。

csw の値は "kstat -p 'cpu::sys:pswitch' 1" でも取得出来ます。

icsw

icsw はインボランタリー(非自発的)なコンテキストスイッチの回数です。csw が自発的に CPU を明け渡しているのに対し、よりプライオリティの高いプロセス等に CPU を横取りされた回数です。

icsw の値は /usr/src/uts/common/disp/disp.c の preempt() 関数の中で CPU_STATS_ADDQ(CPU, sys, inv_swtch, 1); で加算されています。

icsw の値は "kstat -p 'cpu::sys:inv_swtch' 1" でも取得出来ます。

migr

migr はスレッドが他の CPU へ移動した回数です。

migr の値は /usr/src/uts/intel/ia32/ml/swtch.s の "incq CPU_STATS_SYS_CPUMIGRATE(%r13)" や "addl $1, CPU_STATS_SYS_CPUMIGRATE(%esi)" (x86)、/usr/src/uts/sun4/ml/swtch.s の "stx %g2, [%i1 + CPU_STATS_SYS_CPUMIGRATE]" (SPARC) で更新されています。CPU_STATS_SYS_CPUMIGRATE は cpu_stats.sys.cpumigrate のオフセットです。

migr の値は "kstat -p 'cpu::sys:cpumigrate' 1" でも取得出来ます。

smtx

smtx は Mutex 変数で Adaptive Lock がスピンした回数です。

Adaptive Lock で他のスレッドが別のプロセッサ上で Lock を保持している場合(その場合はスピンする)最初のスピンの前に 1 加算されます。最初から Spin Lock の場合は加算されません。

smtx の値は /usr/src/uts/common/os/mutex.c の mutex_vector_enter() 関数の中の CPU_STATS_ADDQ(cpup, sys, mutex_adenters, 1); で加算されています。

smtx の値は "kstat -p 'cpu::sys:mutex_adenters' 1" でも取得出来ます。

srw

srw は RW Lock でスピンした回数です。

srw の値は /usr/src/uts/common/os/rwlock.c の rw_enter_sleep() 関数の中の CPU_STATS_ADDQ(CPU, sys, rw_rdfails, 1); と CPU_STATS_ADDQ(CPU, sys, rw_wrfails, 1); の累積値を足し合わせた値です。

srw の値は "kstat -p 'cpu::sys:rw_rdfails' 1" と "kstat -p 'cpu::sys:rw_wrfails' 1" を足す事でも取得出来ます。

syscl

syscl はシステムコールの回数です。

syscl の値はカーネル内の様々な場所で更新されています。

syscl の値は "kstat -p 'cpu::sys:syscall' 1" でも取得可能です。

usr

usr はユーザモードで使用した CPU 時間の割合です。

usr の値は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数内の get_cpu_mstate() 関数呼び出しで CPU のマイクロステートを読み取って集計しています。get_cpu_mstate() 関数の実装は /usr/src/uts/i86pc/os/machdep.c (x86) と /usr/src/uts/sun4/os/machdep.c (SPARC) にあります。

usr の値は "kstat -p 'cpu::sys:cpu_ticks_user' 1" でも取得出来ます。

sys

sys はカーネルサービスやシステムコールなど、システムモードで使用した CPU 時間の割合です。

sys の値は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数内の get_cpu_mstate() 関数呼び出しで CPU のマイクロステートを読み取って集計しています。get_cpu_mstate() 関数の実装は /usr/src/uts/i86pc/os/machdep.c (x86) と /usr/src/uts/sun4/os/machdep.c (SPARC) にあります。

sys の値は "kstat -p 'cpu::sys:cpu_ticks_kernel' 1" でも取得出来ます。

wt

wt は I/O wait ですが、Solaris 10 では更新されておらず、常に 0 です。その為、このカラムは無視して構いません。

wt の値は "kstat -p 'cpu::sys:cpu_ticks_wait' 1" でも取得出来ます。

idl

idl は CPU が使用されていなかった時間の割合です。

idl の値は /usr/src/uts/common/os/cpu.c の cpu_sys_stats_ks_update() 関数内の get_cpu_mstate() 関数呼び出しで CPU のマイクロステートを読み取って集計しています。get_cpu_mstate() 関数の実装は /usr/src/uts/i86pc/os/machdep.c (x86) と /usr/src/uts/sun4/os/machdep.c (SPARC) にあります。

idl の値は "kstat -p 'cpu::sys:cpu_ticks_idle' 1" でも取得出来ます。

値の見方

usr が多い場合

全ての CPU で usr が 80% 以上になっていて idl が殆ど無い場合は、システムのリソースが十分に利用されていると言って良いでしょう。多くの場合、usr の値が高い事はアプリケーション自体の処理に CPU を使えているという事です。処理のフェイズによってリソースの使い方が変わる場合もありますので、プログラムの実行開始から終了まで観察して下さい。

usr の値は TLB miss でも増加します。この場合はアプリケーション自体の処理と言うよりはリソースの確保に CPU が使われています。SPARC マシンでは trapstat(1M) コマンドで TLB miss の有無を確認する事が出来ます(x86 マシンでは trapstat は使えません)。

 # trapstat -T 1 10
 cpu m size| itlb-miss %tim itsb-miss %tim | dtlb-miss %tim dtsb-miss %tim |%tim
 ----------+-------------------------------+-------------------------------+----
   0 u   8k|        49  0.0         0  0.0 |        27  0.0         0  0.0 | 0.0
   0 u  64k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   0 u 512k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   0 u   4m|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
 - - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - -
   0 k   8k|         7  0.0         0  0.0 |       262  0.0         2  0.0 | 0.0
   0 k  64k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   0 k 512k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   0 k   4m|         0  0.0         0  0.0 |         3  0.0         0  0.0 | 0.0
 ----------+-------------------------------+-------------------------------+----
   1 u   8k|       521  0.0         1  0.0 |        46  0.0         1  0.0 | 0.0
   1 u  64k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   1 u 512k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   1 u   4m|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
 - - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - -
   1 k   8k|       161  0.0         0  0.0 |       222  0.0         9  0.0 | 0.0
   1 k  64k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   1 k 512k|         0  0.0         0  0.0 |         0  0.0         0  0.0 | 0.0
   1 k   4m|         0  0.0         0  0.0 |         7  0.0         0  0.0 | 0.0
 ==========+===============================+===============================+====
       ttl |       738  0.0         1  0.0 |       567  0.0        12  0.0 | 0.0
 ...

trapstat の出力の一番右の %tim のカラムが各 CPU で TLB miss / TSB miss が発生している割合です。この値が 10% を超えている様であれば MPSS を使用する等の対策を取って下さい。trapstat はシステムに対する負荷が高いコマンドなので、あまり頻繁に実施しない様にして下さい。目安としては一番負荷が高い時に 10 秒程度実施します。

usr や sys の値が高く(idl の値がゼロの状態が続いて)、性能が目に見えて劣化している場合は、過負荷である可能性があります。Solaris は高負荷の状況でも非常に粘り強い OS ですが、ネットワークを使ったアプリケーションの場合は "netstat -sP tcp 1" や "dladm show-dev -s -i 1 <NIC>" 等でエラーが発生していないか確認して下さい。

 # dladm show-dev -s -i 1 e1000g0
 		ipackets  rbytes	 ierrors opackets	 obytes	     oerrors
 e1000g0		140895    9390183     0       507       75864       0       
 		ipackets  rbytes	 ierrors opackets	 obytes	     oerrors
 e1000g0		3         192         0       2         340         0       
 		ipackets  rbytes	 ierrors opackets	 obytes	     oerrors
 e1000g0		4         256         0       2         246         0

sys が多い場合

特定の CPU 又は全ての CPU で sys が 20% 以上出ている場合は、カーネルサービスの CPU 使用率が多くなっています。具体的にはシステムコールやスケジューラ、ファイルシステム等が該当します。sys が多い場合はシステムチューニングの余地があるかもしれません。

sys が多く syscl のカラムも高い数値を示している場合、システムコールが sys の発生源になっている可能性があります。まずは prstat で CPU 負荷の高いプロセスを探します。prstat のオプションは -m を付けて下さい。

 % prstat -m 1
    PID USERNAME USR SYS TRP TFL DFL LCK SLP LAT VCX ICX SCL SIG PROCESS/NLWP  
  29044 root     0.0 0.1 0.0 0.0 0.0 0.0 100 0.0  42   0 256   0 prstat/1
  14923 noaccess 0.0 0.0 0.0 0.0 0.0  68  32 0.0  19   1  19   0 java/19
    751 root     0.0 0.0 0.0 0.0 0.0 3.4  97 0.0  41   0 205   0 nscd/29
   9819 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 snmpd/1
  29032 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 in.telnetd/1
  10465 smmsp    0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 sendmail/1
   9666 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 dmispd/1
   9660 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 snmpXdmid/2
   9122 root     0.0 0.0 0.0 0.0 0.0 0.0 100 0.0   0   0   0   0 snmpdx/1

prstat の出力は CPU 使用率の高い順にソートされるので、上の方に表示されているプロセスが一番 CPU 負荷の高いプロセスです。SYS のカラムを見るとそのプロセスがどのくらい sys を発生させているかが分かります。SYS の値が大きいプロセスを見つけたら、そのプロセスに対し truss を掛けてシステムコールの統計を観察します。

 # truss -cp <PID>

時間を多く使っているシステムコールがあれば、そのシステムコールが sys の原因である可能性があります。

syscl の値が小さい場合はシステムコール以外のカーネルサービスが時間を使っている可能性があります。もしインタラプト処理に CPU を使用している場合は intrstat や lockstat -I コマンドで調べる事が可能です。

 # intrstat 1
 # lockstat -kgIW sleep 10

Ultra SPARC T1 の浮動小数点数演算命令シミュレーションが発生していると sys が増えます。Ultra SPARC T1 の浮動小数点数演算命令のシミュレーションが起きているかどうかは kstat で確認する事が出来ます。

 % kstat -p 'unix::fpu_info:fpu_sim*' 1

idl が多い場合

どのプロセッサでも平均して idl が出ている場合は CPU 以外のリソースがボトルネックになっていると考えられます。メモリ、ネットワーク、ディスク等のリソースに不足がないか確認して下さい。

CPU 以外のリソースにも不足が無い場合はリソースが余っている可能性があります。その場合は負荷を増やして挙動を観察してみて下さい。

CPU によって idl の値に偏りがある場合

幾つかの CPU では idl が 0 なのに、残りの CPU では idl が 100 の場合があります。これはプログラムがスケールしていない状態です。その場合は prstat でアプリケーションのスレッド数を確認して下さい。prstat の出力の一番右端、NLWP のカラムがスレッド数です。スレッド数が CPU 数よりも少ない場合は、(可能であれば)スレッド数を増やしてみるのも手です。

スレッド数が CPU の数より多いのにも関わらず CPU が使い切れていない場合はプログラムの作りに問題がある可能性があります。prstat -L でスレッドのアクティビティを観察して下さい。特定のスレッドの処理量が多い場合は、そのスレッドがボトルネックになっている可能性があります。Web Server 等のネットワークサーバでは少数のディスパッチャースレッドと多数のワーカースレッドという構成になっていて、ディスパッチャーの部分がボトルネックになるケースがあります。truss でプログラムの動きをトレースすると、特定のスレッドが張り付いている場合は同じスレッド ID のスレッドばかりが処理を行うので一つの目安となります。

 % prstat -L 1
 % truss -vall -D -p <PID>

特定の CPU に張り付いているスレッドが見られない場合はロックの競合が発生している可能性があります。plockstat でどのくらい競合が発生しているか確認して下さい。例えば、Solaris の標準の malloc() 関数はシングルスレッドで性能が出る様な実装になっており、複数のスレッドで同時にメモリを確保しようとするとロックの競合が発生します。複数のスレッドで同時に動的にメモリを確保する必要がある場合は mtmalloc ライブラリをプリロードするとスケーラビリティが向上します。

 % plockstat -Cv -e 10 -p <PID>

ロックの競合が発生していると lwp_park というシステムコールが多く呼び出されている事があります。lwp_park が発生している場合はスレッドが休止しています。lwp_park の発生は truss コマンドで確認出来ます。また、どの関数コールが lwp_park の原因になっているかは DTrace を使う事で調べる事が出来ます。

 # truss -cp <PID>
 # dtrace -n 'syscall::lwp_park:entry /execname == "<PROCESS NAME>"/ { @[ustack(22)] = count() }'

スレッド数が増やせない、又はこれ以上スケールしないと分かった場合はプログラムの起動数を増やす事が出来るか確認して下さい。特定のポートで Listen する必要がある場合は Zone を構成して IP Address を分散させる事でリソースを有効に使う事が出来ます。併せて psrset でプロセッサセットを作成すると CPU の利用状況が分散されてリソース効率が上がる場合があります。

また、どのプロセッサでも平均して idl が出ているのに、実際は CPU が張り付いているというケースもあります。これを確認するには prstat でスレッド毎の CPU 使用率を観察します。-L オプションを付けるとスレッド毎の統計が表示されます。 prstat -L の CPU のカラムは 100 / CPU 数が最大です。1 つのスレッドの CPU 使用率が 100 / CPU 数に近い値になっている場合はスレッドが CPU に張り付いていると考えられます。該当のスレッドを pbind してあげると、綺麗に 1 つの CPU に張り付くと思います。

 % prstat -L 1
 % pbind -b <CPUID> <PID>/<TID>

intr が多い場合

intr が多く発生している場合は高レベルの割り込みが多く発生している状態です。NIC 等のデバイスに負荷が掛かっている場合によく発生します。インタラプトの詳細は intrstat や lockstat -I で確認して下さい。

 # intrstat 1
 # lockstat -kgIW sleep 10

icsw が多い場合

icsw が多い場合はシステムリソースに対して負荷が高すぎる可能性があります。頻繁にコンテキストスイッチが発生すると性能に大きく影響します。適切な負荷になる様にスレッド数やプロセス数を調節して下さい。

migr が多い場合

migr が 200 を超える場合は /etc/system で rechoose_interval を増やしてみると効果があるかもしれません。

smtx が多い場:

smtx が多い場合は何のロックでスピンしているのか、lockstat や plockstat で確かめて下さい。lockstat はシステム全体の統計、plockstat はプロセスレベルの統計です。

 # lockstat -g -D 10 sleep 10
 # plockstat -Cve 5 -x bufsize=10k -x aggsize=2m -p <PID>

srw が多い場合

srw が多い場合は、同様に lockstat や plockstat で調べてみて下さい。

syscl が多い場合

syscl が多い場合は truss -c や DTrace を使って、どのシステムコールが多く発生しているのかを確認して下さい。

終わりに

以上、mpstat コマンドの出力の読み方をご紹介しました。mpstat は vmstat や iostat コマンドと並んで性能解析の基本的なコマンドです。どんなベンチマークでも mpstat コマンドを使用しない事はありません。特に CPU のコア数やストランド数が多い場>合やスレッド数の多いプログラムでベンチマークを行う際には必須のコマンドです。是非ご活用下さい。

参考文献

http://blogs.sun.com/yappri/date/20090420 2009年 4月 20日 月曜日

ネットワークを調査する 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 を使用すると、更に詳細な分析を行う事も可能です。是非ご活用下さい。