あけましておめでとうございます。 今年もよろしくお願いします。

La Fonera (La Fonera+) のブート・ローダ RedBoot は、 TFTP サーバに置いたカーネルを load して起動することができる。 したがって、 TFTP サーバから load したカーネルで root ファイル・システムを NFS マウントすれば、 フラッシュ・メモリを使わずにブートすること (ディスクレス・ブート、というか flashless boot) ができる。

La Fonera のようなルータをディスクレスにして 何が嬉しいのかと思う人もいるかもしれないが、 ルータのように常時ネットワークにつなぐものだからこそ、 ネットワークにつないでいないと使えないという ディスクレス最大の欠点が欠点にならないわけで、 むしろルータこそ積極的にディスクレスにすべきではなかろうか。

ディスクレス化することによるメリットは数多い。 なんといっても最大のメリットは、 フラッシュ・メモリを書き換えること無く、 手軽にファームウェアを入れ替えられる (OpenWrt や DD-WRT など) こと。 フラッシュ・メモリを書き換える時間が節約できるし、 書き換え回数を気にする必要もなくなるわけで、 心置き無くファームウェアのデバッグを行なえる。 また、 NFS を使えばフラッシュ・メモリの容量をはるかに超えるディスク領域を使えるので、 セルフ・コンパイル環境の構築なども容易に行なうことができる。

試しに、 La Fonera のフラッシュ・メモリを書き換えること無く DD-WRT をブートさせてみる。

まず、 DD-WRT の root ファイル・システムを NFS サーバ上に展開する。 ここでは例として /nfs/dd-wrt に展開した。 /usr/sbin/udhcpc の実行を抑制するため (理由は後述) に、 /nfs/dd-wrt/usr/sbin/udhcpc を削除しておく。

senri:/tmp # wget "http://www.dd-wrt.com/dd-wrtv2/downloads/release candidates/DD-WRT v24 RC6.2/Atheros WiSoc/Fonera/root.fs" --09:22:37-- http://www.dd-wrt.com/dd-wrtv2/downloads/release%20candidates/DD-WRT%20v24%20RC6.2/Atheros%20WiSoc/Fonera/root.fs => `root.fs' ... 09:22:46 (335.56 KB/s) - `root.fs' saved [2834432/2834432] senri:/tmp # unsquashfs.dd-wrt -dest /nfs/dd-wrt root.fs Reading a different endian SQUASHFS filesystem on root.fs created 347 files created 61 directories created 159 symlinks created 0 devices created 0 fifos senri:/tmp # rm /nfs/dd-wrt/usr/sbin/udhcpc

次に DD-WRT のカーネルを改変して、 root ファイル・システムを NFS マウントできるようにする。 DD-WRT のソースを取得:

senri:/usr/local/src % svn co svn://svn.dd-wrt.com/DD-WRT A DD-WRT/tools A DD-WRT/tools/addpattern_gs A DD-WRT/tools/uemf.h ...

La Fonera 用のカーネルは、 DD-WRT/src/linux/ar531x/linux-2.6.23 にある。

SVN revision 8745 の場合は Linux 2.6.23.12 ベース。

ビルド用ディレクトリ /usr/local/src/linux-2.6.23.12-dd-wrt を作って、 DD-WRT のデフォルトのカーネル設定ファイル .config_generic をコピーし、 make menuconfig を実行:

senri:/usr/local/src % mkdir /usr/local/src/linux-2.6.23.12-dd-wrt senri:/usr/local/src % cd DD-WRT/src/linux/ar531x/linux-2.6.23 senri:/usr/local/src/DD-WRT/src/linux/ar531x/linux-2.6.23 % make O=/usr/local/src/linux-2.6.23.12-dd-wrt menuconfig ... senri:/usr/local/src/DD-WRT/src/linux/ar531x/linux-2.6.23 % cp .config_generic /usr/local/src/linux-2.6.23.12-dd-wrt/ senri:/usr/local/src/DD-WRT/src/linux/ar531x/linux-2.6.23 % cd /usr/local/src/linux-2.6.23.12-dd-wrt senri:/usr/local/src/linux-2.6.23.12-dd-wrt % make menuconfig

root ファイル・システムを NFS マウントするために必要な変更は以下の通り:

まず、 カーネルによる IP アドレス自動取得機能を有効にする:

-> Networking -> Networking support (NET [=y]) -> Networking options -> TCP/IP networking (INET [=y]) -> IP: kernel level autoconfiguration (IP_PNP [=y]) -> IP: DHCP support (IP_PNP_DHCP [=y])

DD-WRT のデフォルト設定では、 ネットワーク・ドライバ AR2313 がモジュールになっているので、 カーネル組み込み (built-in) に変更する:

-> Device Drivers -> Network device support (NETDEVICES [=y]) -> Ethernet (10 or 100Mbit) (NET_ETHERNET [=y]) -> AR2313 Ethernet support (AR2313 [=y])

そして NFS サポートを有効にする:

-> File systems -> Network File Systems -> NFS file system support (NFS_FS [=y]) -> Provide NFSv3 client support (NFS_V3 [=y]) -> Root file system on NFS (ROOT_NFS [=y])

root ファイル・システムはカーネルがマウントするので mount コマンドは使用しないが、 La Fonera 用の DD-WRT の mount コマンド (busybox に含まれる) は、 NFS をサポートしていないので注意が必要である。 NFS サーバ上の root ディレクトリ /nfs/dd-wrt には、 NFS マウントをサポートした mount コマンドをインストールしておいたほうが便利。

RedBoot の exec コマンドでカーネル・コマンドラインを指定しても、 なぜか無視される (バグ?) ので、 カーネルのデフォルト・コマンドラインを変更しておく:

-> Kernel hacking -> Default kernel command string (CMDLINE)

カーネル・コマンドラインとして以下を設定:

console=ttyS0,115200 ip=on root=/dev/nfs nfsroot=/nfs/dd-wrt,nolock

以上まとめると、 カーネル設定ファイル .config の変更箇所は以下の通り:

CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_AR2313=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y CONFIG_ROOT_NFS=y CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_NFS_COMMON=y CONFIG_SUNRPC=y CONFIG_CMDLINE="console=ttyS0,115200 ip=on root=/dev/nfs nfsroot=/nfs/dd-wrt,nolock"

make して TFTP サーバに置く:

senri:/usr/local/src/linux-2.6.23.12-dd-wrt % make make -C /usr/local/src/DD-WRT/src/linux/ar531x/linux-2.6.23 O=/usr/local/src/linux-2.6.23.12-dd-wrt GEN /usr/local/src/linux-2.6.23.12-dd-wrt/Makefile ... LD vmlinux SYSMAP System.map ... senri:/usr/local/src/linux-2.6.23.12-dd-wrt % mips-linux-uclibc-objcopy -O binary vmlinux /var/tftp/vmlinux.bin

La Fonera で読み込んでブートさせる... といいたいところだが、 DD-WRT のカーネルは、 flash RAM に「nvram」という名前の区画がないと Kernel panic を起こす:

RedBoot> load -r -b 0x80041000 vmlinux.bin Using default protocol (TFTP) Raw file loaded 0x80041000-0x8031cbb3, assumed entry at 0x80041000 RedBoot> exec Now booting linux kernel: Base address 0x80030000 Entry 0x80041000 Cmdline : Linux version 2.6.23.12 (sengoku@senri.gcd.org) (gcc version 4.1.2) #14 Wed Jan 2 13:20:19 JST 2008 ... Unhandled kernel unaligned access[#1]: Cpu 0 $ 0 : 00000000 0000006e ffffffed 00000000 ... Kernel panic - not syncing: Attempted to kill init!

flash-less boot の主旨には反するが (^^;)、 nvram 区画を作って再度ブートを試みる。

もちろん、 flash を一切参照しないファームウェアを作ることも可能ではあるが、 わずか 64k byte の flash 領域を確保するだけで、 既存のファームウェアをほとんどそのまま流用できるのであれば、 費用対効果の高い flash の使い方と言えるのではないだろうか。

nvram 区画の内容は「空っぽ」でも構わないのであるが、 ついでなので他の DD-WRT マシンで設定した nvram (nvram.bin) をコピーすれば、 設定の手間が省ける。

DD-WRT のデフォルト設定では、 ath0 (無線LAN) と eth0 (WAN) がブリッジとして動作する設定になっていて、 ブート途中で一時的に eth0 を停止する (ifconfig eth0 down あるいは ifconfig eth0 0.0.0.0)。 当然、eth0 を止めた瞬間に NFS サーバと通信できなくなり、 「nfs: server not responding, still trying」という ログを出し続けてハングしてしまう。 したがって、 eth0 を止めない設定にしておく必要がある。 例えば、 NFS サーバ上の root ディレクトリから /usr/sbin/udhcpc を削除した上で、 「WAN Connection Type」を DHCP に設定する。

ついで^2 に、 La Fonera+ には、 「image2」という名前の普段は使われていない区画がある (「image」区画が壊れた場合の非常用) ので削除しておく (fis delete image2)。

RedBoot> fis delete image2 Delete image 'image2' - continue (y/n)? y ... Erase from 0xa8660000-0xa87a0000: .................... ... Erase from 0xa87e0000-0xa87f0000: . ... Program from 0x80ff0000-0x81000000 at 0xa87e0000: . RedBoot> load -r -b 0x80041000 nvram.bin Using default protocol (TFTP) Raw file loaded 0x80041000-0x80050fff, assumed entry at 0x80041000 RedBoot> fis create -b 0x80041000 -f 0xA87D0000 -l 0x00010000 nvram ... Erase from 0xa87d0000-0xa87e0000: . ... Program from 0x80041000-0x80051000 at 0xa87d0000: . ... Erase from 0xa87e0000-0xa87f0000: . ... Program from 0x80ff0000-0x81000000 at 0xa87e0000: . RedBoot> fis list Name FLASH addr Mem addr Length Entry point RedBoot 0xA8000000 0xA8000000 0x00030000 0x00000000 loader 0xA8030000 0x80100000 0x00010000 0x80100000 image 0xA8040000 0x80040400 0x00240230 0x80040400 nvram 0xA87D0000 0xA87D0000 0x00010000 0x80041000 FIS directory 0xA87E0000 0xA87E0000 0x0000F000 0x00000000 RedBoot config 0xA87EF000 0xA87EF000 0x00001000 0x00000000

flash がこの状態でも、 La Fonera+ のオリジナル・ファームウェアは正常に起動する。 また、 ここでは La Fonera+ を使用しているが、 La Fonera でも同様に nvram 区画を作ればよい。

より正確に言うと、 区画の個数が同じ (/dev/mtd9 が board_config) でないと、 オリジナル・ファームウェアでは fonsmcd が異常終了してしまって、 FON ルータが接続されていないと FON にみなされてしまう。 image2 を削除して nvram を追加すれば区画の個数は変わらないので、 fonsmcd を正常に動かすことができる。

ついでに言うと、 区画の個数が変化してしまっても、 /usr/sbin/fonsmcd ファイル中の「/dev/mtd9ro」という部分を変更すれば、 この問題は回避できる。 MTD パーティションの番号をハードコーディングしてしまっているのは、 この部分だけだと思われる。

再度ブート:

RedBoot> load -r -b 0x80041000 vmlinux.bin Using default protocol (TFTP) Raw file loaded 0x80041000-0x8031cbb3, assumed entry at 0x80041000 RedBoot> exec Now booting linux kernel: Base address 0x80030000 Entry 0x80041000 Cmdline : Linux version 2.6.23.12 (sengoku@senri.gcd.org) (gcc version 4.1.2) #14 Wed Jan 2 13:20:19 JST 2008 ... IP-Config: Got DHCP answer from 172.16.255.254, my address is 172.16.191.230 IP-Config: Complete: device=eth0, addr=172.16.191.230, mask=255.255.0.0, gw=172.16.255.254, host=172.16.191.230, domain=, nis-domain=(none), bootserver=172.16.255.254, rootserver=172.16.255.254, rootpath= Looking up port of RPC 100003/2 on 172.16.255.254 Looking up port of RPC 100005/1 on 172.16.255.254 VFS: Mounted root (nfs filesystem) readonly. Mounted devfs on /dev Freeing unused kernel memory: 140k freed ... DD-WRT v24 std (c) 2008 NewMedia-NET GmbH Release: 01/02/08 (SVN revision: 8743) DD-WRT login: root Password: XXXXXXXX ========================================================== ____ ___ __ ______ _____ ____ _ _ | _ \| _ \ \ \ / / _ \_ _| __ _|___ \| || | || | || ||____\ \ /\ / /| |_) || | \ \ / / __) | || | ||_| ||_||_____\ V V / | _ < | | \ V / / __/|__ _| |___/|___/ \_/\_/ |_| \_\|_| \_/ |_____| |_| DD-WRT v24 http://www.dd-wrt.com ========================================================== BusyBox v1.4.2 (2008-01-02 03:34:20 CET) Built-in shell (ash) Enter 'help' for a list of built-in commands. root@DD-WRT:~# cat /proc/mounts rootfs / rootfs rw 0 0 /dev/root / nfs ro,vers=2,rsize=4096,wsize=4096,hard,nolock,proto=udp,timeo=10,retrans=2,sec=sys,addr=172.16.255.254 0 0 none /dev devfs rw 0 0 proc /proc proc rw 0 0 sysfs /sys sysfs rw 0 0 ramfs /tmp ramfs rw 0 0 devpts /dev/pts devpts rw 0 0 root@DD-WRT:~#

NFS サーバに置いた DD-WRT の root ディレクトリ /nfs/dd-wrt が、 無事 / にマウントできている。