Solaris で SoftEther もどきを動かそう/其の2目次†ご注意†
お知らせ†(2005-02-19)†以前、仮想 NIC ドライバのドライバ名を "sfe" としていましたが、同じ名前の Solaris 用のフリーの NIC ドライバがあることが分かったため、名前を "ste" に変更いたしました。もし、検索サイトなどで、x86 Solaris 用の NIC ドライバを探してこの ページに来られたかたがいらっしゃいましたら、お探しのドライバは http://homepage2.nifty.com/mrym3/taiyodo/eng/ のものかと思います。 (2006-11-05)†ste ドライバの実装を大幅に変更しました。変更点については変更点の概要、変更点の解説、
及び|ste.c をご参照ください。
論理的にはパフォーマンスの改善が見込まれる・・はずだったのですが、仮想ハブの方の実装がネック
になっているようで、実測値はほとんど変わりませんでした。(泣) (2012-01-03)†Solaris 11 でコンパイル可能なように変更をおこないました。OpenIndiana でもコンパイル、ロード可能です。 変更点の概要†其の1で作ったものに以下の変更を加えました。主としては、其の1で課題としていた、プロキシサーバ経由での接続と、パフォーマンスの向上です。酷かったパフォーマンスもちょっとはましになったと思います。(笑) 仮想 NIC ドライバへの変更†
仮想 NIC デーモンへの変更†
仮想ハブへの変更†
仮想ハブへのプロキシサーバ経由の接続は、HTTP の CONNECT メソッドを利用しています。ですので、プロキシサーバが CONNECT メッソッドをサポートしていないと、この方法は使えません。ただ、HTTPS/SSL 接続を謳っているプロキシサーバであれば、CONNECT メソッドをサポートしていると思います。(私の認識が間違っていたらごめんなさい。) ソースファイルとダウンロード†
ソースコードはこちらから参照していただくこともできます。 動作確認済み Solaris バージョン†本プログラム動作確認状況は以下のようになっています。 ○:動作確認済み ×:動作不可 ?:未確認 -:該当なし 変更点の解説†ste:仮想 NIC ドライバ†其の1のドライバでは、仮想ハブデーモンからオープンされた STREAM の stream head の high water mark 値(ユーザ空間と、カーネル空間の間のバッファのようなものと考えてください)がデフォルトのままだったので、非常に小さく(おそらく1パケット分だけ)安易に溢れてしまいパケットが取りこぼれる要因となっていました。ここを 20K byte ほどに設定しパケットの取りこぼしが少なくなるようにしました。 sted: 仮想 NIC デーモン†プロキシサーバ接続機能†起動時の -p オプションで、プロキシサーバ名、ポート番号を指定できるようにし、-p が指定された場合にはまず、プロキシーサーバに接続しにいき、CONNECT メッソッドをつかって仮想ハブへの接続を要求するようにしました。プロキシサーバに投げられるリクエストは以下のような感じです。 CONNECT <仮想ハブ名>:<ポート番号> HTTP/1.1<CR><LF> Host: <仮想ハブ名>:<ポート番号><CR><LF> <CR><LF> 正直いいますと、プロキシサーバ経由で外部と接続できるテスト環境がなかったので、完全なテストはできておりません。私が行ったのは、自宅のマシンからインターネット上で公開されている HTTPS 接続が可能なプロキシーサーバを経由しての接続テストです。 パフ ォーマンスの向上†仮想 NIC ドライバーから getmsg(2) で受け取るメッセージの最大長は Ethernet フレーム長と同じ 1514 byte になります。これをそのまま TCP のデータ部(1460 bytes)として仮想ハブに送ろうとすると、どうしても 54 byte 余ってしまい、結果として、1 Ethernet フレームを伝送するのに 2 パケット必要で、かつ 2 つ目のパケットはほとんどデータを含んでいないパケットになってしまいます。 これではとても効率が悪いので、getmsg(2) から受け取ったメッセージをすぐには仮想ハブに転送せず、一旦ローカルのバッファに溜めておき、バッファが一定量までたまったらまとめて転送するようにしました。ただ、これだと 単発の ICMP パケットや、UDP パケットなどがすぐに相手にとどかない恐れがあるので、フレームサイズが 1514 bytes より小さい場合には、無差別にすぐに仮想ハブに転送するようにしました。 また、一定時間内に(0.4 秒)バッファが定量値までたまらなかった場合にはその時点でバッファにあるメッセージを仮想ハブに転送します。このあたりはまだまだ調整の余地があると思ってます。 デーモン化†sted が実行されると、/dev/ste のオープンし、仮想ハブへの接続をおこないます。これらが正常に完了したすると以下を実行し、自身をデーモン化するようにしました。
標準出力、エラー出力先をクローズしてしまったので、エラーメッセージ等は syslog に出力するようにしました。ただし、-d オプションにてデバッグレベルを「1」以上にセットした場合にはフォアグラウンドで実行が継続され(fork(2)しない)、標準エラー出力にデバッグ情報を出力します。 stehub: 仮想 ハブ†仮想ハブについては相変わらずあまり手を加えていません。ただ、なぜか recv(3SOCKET)で使うバッファサイズを 500 bytes としていたので、これを 32 Kbytes に増やしました。また、仮想 NIC デーモンと同様に自身を fork(2) しバックグラウンドで実行されるようにしました。 インストール†コンパイル&インストール†configure スクリプトにて Makefile を作成し、つづけて make を実行することで、ドライバである ste と stehub, sted がコンパイルれます。configure スクリプトの中で isainfo(1) が呼ばれるので、64bit Solaris であれば 64bit モジュールが、32bit Solaris であれば 32bit モジュールが作成されます。 # ./configure checking for gcc... gcc checking for C compiler default output file name... a.out checking whether the C compiler works... yes checking whether we are cross compiling... no checking for suffix of executables... checking for suffix of object files... o checking whether we are using the GNU C compiler... yes checking whether gcc accepts -g... yes checking for gcc option to accept ANSI C... none needed checking for isainfo... yes checking for uname... yes checking for cut... yes configure: creating ./config.status config.status: creating Makefile # # make gcc -c -O -D_KERNEL -D_SYSCALL32 -m64 -DSOL10 ste.c -o ste.o /usr/ccs/bin/ld -dn -r ste.o -o ste gcc -c -g -O2 sted.c -o sted.o gcc -c -g -O2 sted_socket.c -o sted_socket.o gcc -c -g -O2 dlpiutil.c -o dlpiutil.o gcc -g -O2 -lsocket -lnsl sted.o sted_socket.o dlpiutil.o -o sted gcc -c -g -O2 stehub.c -o stehub.o gcc -g -O2 -lsocket -lnsl stehub.o -o stehub # ste ドライバのインストール、およびカーネルへのロード、ste デバイスノードの作成は make install で行います。また、今回から仮想 NIC デーモン(sted)、仮想ハブ(stehub)を / usr/local/bin の下にコピーするようにしました。 # make install /usr/sbin/install -s -f /kernel/drv/sparcv9 -m 0755 -u root -g sys ste /usr/sbin/install -s -f /kernel/drv -m 0644 -u root -g sys ste.conf /usr/sbin/install -s -d /usr/local/bin /usr/sbin/install -s -f /usr/local/bin -m 0755 -u root sted /usr/sbin/install -s -f /usr/local/bin -m 0755 -u root stehub /usr/sbin/add_drv ste # 仮想 NIC のデバイス名は ste になります。 # ls -l /dev/ste lrwxrwxrwx 1 root other 29 10月 28日 23:37 /dev/ste -> ../devices/pseudo/clone@0:ste # ls -l /devices/pseudo/clone@0:ste crw------- 1 root sys 11,215 12月 23日 01:43 /devices/pseudo/clone@0:ste # アンインストール†ドライバのアンインストールは make uninstall で行います。 # make uninstall /usr/sbin/rem_drv ste /bin/rm /kernel/drv/sparcv9/ste /bin/rm /kernel/drv/ste.conf /bin/rm /usr/local/bin/sted /bin/rm /usr/local/bin/stehub # 同時に ste ドライバのアンロード、ste デバイスノードの削除も行われますが、ifconfig などで ste ドライバが利用中の場合、ドライバのアンロードは失敗します。この場合システムを再起動後に完全に削除されます。 # make uninstall /usr/sbin/rem_drv ste デバイスは使用中です Cannot unload module: ste Will be unloaded upon reboot. /bin/rm /kernel/drv/sparcv9/ste /bin/rm /kernel/drv/ste.conf /bin/rm /usr/local/bin/sted /bin/rm /usr/local/bin/stehub # 使い方†仮想 NIC ドライバ、仮想 NIC デーモン、仮想ハブデーモンの使い方をご説明します。基本的に使い方は其の1と変わっていません。 仮想 NIC ドライバ†仮想 NIC のデバイス名は ste で、/dev/ste からアクセスできます。ste ドライバは実 NIC があるかのように振舞いますので、ifconfig や snoop コマンドで普通に利用できます。
# ifconfig ste0 plumb # ifconfig ste0 10.0.0.55 up # ifconfig -a lo0: flags=2001000849<UP,LOOPBACK,RUNNING,MULTICAST,IPv4,VIRTUAL> mtu 8232 index 1 inet 127.0.0.1 netmask ff000000 hme0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 10 inet 172.29.73.55 netmask ffffff00 broadcast 172.29.73.255 ether 8:0:20:c6:69:c7 ste0: flags=1000843<UP,BROADCAST,RUNNING,MULTICAST,IPv4> mtu 1500 index 94 inet 10.0.0.55 netmask ff000000 broadcast 10.255.255.255 ether a:0:20:69:c:d1 ^^^^^^^^^^^^^^ <-- 自動割当 # snoop -d ste0 Using device /dev/ste (promiscuous mode) 10.0.0.90 -> (broadcast) ARP C Who is 10.0.0.55, 10.0.0.55 ? 10.0.0.55 -> 10.0.0.90 ARP R 10.0.0.55, 10.0.0.55 is 8:0:20:0:0:55 10.0.0.90 -> 10.0.0.55 ICMP Echo request (ID: 543 Sequence number: 0) 10.0.0.55 -> 10.0.0.90 ICMP Echo reply (ID: 543 Sequence number: 0) # ste は実デバイスが存在しない仮想デバイスなので、/kernel/drv/ste.conf がその代わりとなります。(参照: man driver.conf(4)) デフォルトではインスタンス 0(=ste0)だけが有効なインスタンスになっています。 ste.conf ファイルの中身 name="ste" parent="pseudo" instance=0; 上記の instance=0 の「0」が仮想デバイスのインスタンスになります。 以下のようにインスタンス 1、インスタンス 2、という行を追加すればいくらでも仮想 ste デバイスが作ることができます。(ste1 や ste2 に相当) name="ste" parent="pseudo" instance=1; name="ste" parent="pseudo" instance=2; 仮想ハブ(プログラム名 stehub)†仮想 NIC デーモンからの接続を待ち受けるポートを -p オプションで指定できるようになりました。オプションを指定しない場合にはデフォルトで 80 が使われます。 Usage: stehub [ -p port] [-d level] -p port : Port nubmer -d level : Debug level[0-1] # stehub -p 8888 Going to background mode # 仮想 NIC デーモン(プログラム名 sted)†起動時に ste デバイスのインスタンス番号と接続する仮想ハブのホスト名、ポート番号、また 必要であればプロキシサーバ名、ポート番号を指定します。なにも指定されなかった場合、デフォルトのインスタンス番号は 0(ste0)、デフォルトで接続するホスト名は localhost で、接続するポート番号は 80です。 仮想ハブ、プロキシサーバのポート番号はそれぞれのホスト名の後にコロン「:」をつけて指定します。ポートが明示的に指定されなかった場合にはデフォルトで 80 が使われます。 Usage: sted [ -i instance] [-h hub[:port]] [ -p proxy[:port]] [-d level] -i instance : Instance number of the ste device -h hub[:port] : Virtual HUB and its port number -p proxy[:port] : Proxy server and its port number -d level : Debug level[0-3] # sted -i 0 -h hub.example.com:8888 Successfully connected with HUB Going to background mode # 設定例†Host to Host (プロキシサーバ経由)†それぞれ別々の物理ネットワークに繋がった2つのホストを、仮想ハブを通じで、同一ネットワークに繋がっているように見せるための設定です。 其の1の設定例と同一の設定も行えますが、ここでは新しい機能であるプロキシサーバ経由での利用例についてご説明します。 以下の例では分かりやすくするために、仮想ハブと仮想 NIC デーモンが起動されているホストを別のホストにしていますが、仮想ハブは仮想 NIC デーモンが起動されているホスト上で動作させても問題ありません。
ホストAの設定†
ホストBの設定†
ホストCの設定†
Host to LAN(プロキシサーバ経由)†遠隔地にあるホストをローカルの LAN に参加させるための設定です。 其の1設定例でご説明したのと同じ設定も行えますが、今回はプロキシサーバを経由してローカルネットワークを外部ホストと共有する設定例についてご説明します。 SoftEther では、Windows XP/2003 サーバに付属しているブリッジドライバを使って、仮想 NIC と実 NIC 間でブリッジ接続を構成することで実現させてるようです。Solaris にはこのような2つの NIC をブリッジ接続させるようなドライバーは提供されていませんので、「Solaris をスイッチングハブにしよう」でご紹介しているブリッジモジュール(brdg)を利用することにします。 ただし、brdg モジュールはもともとこのような使い方を想定していなかったので、ste ドライバと brdg モジュールの共生についてはかなり不安があります。ste ドライバ単体で使うよりもかなり危険(パニック、システムハング等)が高くなることをご承知の上お試しくださいませ。私のテスト環境でしばらくこの設定で運用したかぎりはパニック等の問題は発生しませんでした。
ホストAの設定†
ホストBの設定†
ホストCの設定†
既知の問題†実は、上記設定ではホスト B と ホスト C の直接の通信ができません。 もちろんホスト B からホスト D など他のホストとの通信は可能なのですが、ブリッジとして動作しているホスト C とだけは通信することができないのです。これはブリッジモジュールの仕様上の制限でして、ブリッジモジュールからホスト C 上の実 NIC ドライバに渡されたホスト C 宛ての Ethernet フレームが IP モジュールに渡されることなくケーブル上に送信されてしまうためです。
今後の課題† |