Thursday, April 24, 2008

64bit kernel with 32bit userland

あぁやっとVMware Serverが安定しました。
やはり64bit userlandがダメだったみたいです。

i386 sid に apt-get install linux-image-2.6-amd64 で。
module をそのまま build してつかえるのか心配でしたが、問題なさげです。

ともあれ、一応4GBのメモリを使うことができているのでよしとしますか。

Tuesday, April 15, 2008

Reverting to 32bit

64bit にしてからVMware ServerがSignal11やへんなハングアップでぽこぽこ落ちるのでしかたなく32bitに戻すことにした。
作業は32bit->64bitと同じだが、将来のことを考えて / を二つ用意してどちらでも起動できるようにしよう。

そんなわけで、今回は物理的なHDDを1台用意してパーティションを適切に設定し、別のマシンでとにかくインストール。
んで、/etc, /var, /home あたりをコピーしてサーバのboot driveと交換。
これによりdowntimeを削減。

しかし /home のコピーはけっこう時間かかった。なにせSATAといえど古い80GBとかのDISKなので。

今のところ安定している模様だが、やはりメモリは3.3GB程度しか使えないことになってるので、カーネルだけ64bitにしてみようかと画策中である。

Thursday, April 3, 2008

64bit Migration

自宅のサーバっていうかルータマシン兼VMware Hostを64bit化(amd64 arch)した記録。

1. パーティションの確認。
/ と /home しかないので、とりあえず /var /etc /boot /usr など適当に /home/root に退避。

2. shutdown してDebian lenny amd64 インストーラをUSBメモリから起動

3. ディスクのdetect order が違っていて構成がおかしいが、とにかく以前の / を探してインストール

4. 案の定、grub ではまる。/ の場所が (hd0)ではなく、(hd2) になっていたので,もっかいインストールしなおし

5. そのまま起動はできないので grub のエントリをいじりつつ起動。つか grub2 でだいぶかわっててはまる。

6. まぁ起動できたので退避していたデータをうつす。

7. まずネットワークだ。っていうんで /etc/network/ の下を適当に restore.
pppoeも問題ないようだ。

8. VMware Server 1.0.5をいれる。32bitバイナリどうやって動かすんですか。と、はまったが、apt-get install ia32-libs でいいみたい。なるほど。
module のコンパイルができねえので vmware-anyany-update-116.tar.gz なるものをゲット。
これでまぁなんとかなった。が、vmware-server-console をつないでみると vmware-serverd が即死する模様。
なんだがコンディションがよくなさそうなので再起動したらなおった。謎。

9. 次に LDAP だ。 /etc/ldap/ /var/lib/ldap/ を restore するも slapd がSegvして起動しない。
32bitのデータは64bitでそのまま使えないのだろうか。
ということで、別のホストでdb_dumpしてdb_loadしたりしたら起動するようになった。
が、ldapsearch してもなにもかえってこない。slapcatではデータがあるように見える。
そんなわけで延々はまっていたが、slapcat で ldif をバックアップしていったんデータベースを消去。
slapadd で restore したらなんとかなった。まったくslapdはデリケートすぎる。やれやれ。

10. VMware Host と Guest 間の IPv6通信ができないぞ。
あぁこれは、ハードウェアチェックサムを disable しないといかんのだった。
ethtool -K eth1 tx off
でオケ。つうか /etc/rc.local に書いてたんで、これを restore. iptables-resotre もここに書いてた。

11. Guest からIPv4通信がまったくできないぞ。外に。
あぁこれは、どうやらルーターとして動いてないな。
echo 1 > /proc/sys/net/ipv4/conf/all/forwarding
はあはあ。つうか /etc/sysctl.conf を restore.

というわけで、5時間強ほどかかって完了。

教訓。slapd のバックアップは slapcat でやっといたほうがいいな。

以上。

Wednesday, March 5, 2008

nscd and getnameinfo

nscdがなんかへん。


% ruby -rsocket -e 'p Socket.getnameinfo([nil, 80, "127.0.0.1"])'
["localhost.localdomain", "80"]
% sudo /etc/init.d/nscd stop
Stopping Name Service Cache Daemon: nscd.
% ruby -rsocket -e 'p Socket.getnameinfo([nil, 80, "127.0.0.1"])'
["localhost.localdomain", "www"]
% dpkg -s nscd | grep "^Version"
Version: 2.7-9


うーん?

Friday, February 8, 2008

Jasper - Kimura Kaela

木村カエラのJasper.
なーんかこの曲は電気っぽいとおもったら卓球作曲らしい。
なるほど

Thursday, February 7, 2008

Google Analytics with MoinMoin

Google AnalyticsをMoinMoinWikiで使う方法。

設定ファイルの page_footer2 に 例の js を書けばよい。

    page_footer2 = """
<script type="text/javascript">var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-XXXXXX-X");
pageTracker._initData();
pageTracker._trackPageview();
</script>
"""

これで各ページの </body>タグの直前にスクリプトが挿入される。

Is UHP really required?

そもそも、プロトコルを全部UDPでやれば、初期接続がクライアントからであるかぎり、UHPなんて考えなくてもいいのではなかろうか。

再送とかのチェックがめんどうではあるけども、それはデータ転送においても同じわけで。
まぁUHPつかえないルータの場合の考慮はどうすんだという問題もあるが、そのへんは要件次第か。

Wednesday, February 6, 2008

UDP Hole Punching その2

どうやら昨日書いた手法は特許とられてるらしい。ひどい話である。
・TCPでなんらかのデータ送信の後、UDPで補足データを送信する
という請求事項にひっかかるのだとか。(特許公開番号:2007-502585)

まぁいろいろ考えたが、最初のTCPによるセッション初期化をUDPでやっちまえばいい気がしてきたので、次のように変更。

1. C UDP::UHPInitialize -- NOP
2. S UDP::UHPInitializeOK -- SESSIONID < UNIQUE ID >
3. C TCP::UHPComplete -- FLAG < 0(FAIL) | 1(SUCCESS) >[, SESSIONID < UNIQUE ID > ]
4. S TCP::UHPCompleteOK -- NOP

まぁいいんでないかなあ。初期化失敗したら知らんぷり or TCPで続ける。
あとUHPを行う場合、クライアントのUDPソースポートも固定(bind())しておかないといつのまにか通信できなくなる可能性があるので注意すべき。
あとほんとに目的のサーバから送られてきたかどうかのチェックとか。

Tuesday, February 5, 2008

UDP Hole Punching

仕事でUDPのデータストリームを扱っていて、さらにクライアントはNAT超えを考慮しなくてはならないということで、UDPのNAT超えでよく使われる手法、UDP Hole Punching (UHP) というものを実装することになった。

UDP Hole Punchingというのはルータに動的に空けられたNATテーブルの穴を逆から叩くことにより、NATの中のクライアントとUDP通信を可能にする技術であるからして。

さて、TCPのコントロールコネクションはもともとあるので、そのプロトコル上に UHP のネゴシエーションを付け加える形にした。

1. TCP C: UHPInitialize <NOP>
2. TCP S: UHPInitializeOK <SESSION ID> <SERVER UDP PORT>
3. UDP C: UHPRequest <SESSION ID>
4. UDP S: UHPRequestOK <NOP>
5. TCP C: UHPComplete <SUCCESS | FAILED>
6. TCP S: UHPCompleteOK <NOP>

3と4で UDP Hole Punching を行うわけだが、UDPなのでロストするかもしれない。なので両者とも数回再送を試みる。
最終的に、クライアントが4の UHPRequestOK を受け取る事ができればUHPは成功であり、
5 の UHPComplete で SUCCESS を返すわけである。

3もしくは4をロストしたり、そもそも UHP が不可能な NAT 環境であった場合、FAILEDを返すことにより TCP へ Fallback するなりなんなりするようにする。といった寸法である。

以上のシーケンスをRubyでテストコード書いて(仕事のコードなので公開はできないが)実行してみたのだが、うまくいかない。
NAT なしの LAN内であれば動くのでアルゴリズム的な部分は間違ってない(と、思う)。

ルータが特殊なのかと思っていたのだが、帰宅途中で罠に気がついた。

実は、テストしているサーバは複数の Network Interface をもっている。
アドレスがプライベートで NAT の中にある eth0 と、実験でつかっている(つもり)のグローバルアドレスを持つ eth1 であり、default route は eth0 の NATルータである。

そして、サーバでudp socketがbind() しているアドレスは '0.0.0.0' である。
つまり、クライアントがグローバルアドレスに sendto()し、サーバが recvfrom() により取得したした client socket address へ sendto() を返す場合、サーバの source addres はカーネルが勝手に決めているのであり、基本的に default routeが使われるわけだから、eth0のプライベートアドレスになってしまう。
要するにサーバもNAT内あるものとして動作をしていた、というわけなのである。
UHP は NAT(client)からNAT(server) では仲介サーバが居ない限り不可能である。

今回はそういったケースは考慮しないので、素直にサーバの bind address をグローバルなものにして再実験をしたところ、うまく動作した。

教訓。udp socket を '0.0.0.0' に bind()してlistenするときは複数の interface や routing がないか注意しよう。

my first post

blogger.comでブログ書くことにしました。
自前サーバでCMSのアップグレードやメンテナンスをしたり、コメントスパムと格闘したり、
テンプレートで頭を悩ますのはもううんざりなのです!

というわけでございまして。
適当に続けていこうと思います。