Proxy DHCP サーバで PXE ブート

ずっと PXE ブートはやってみたかったんだけど,すでに(PXE に対応しない)DHCP サーバがあがっている環境なので半ば諦めていた。もう一台 PXE に対応した DHCP サーバを立てるというのも一つの手*1なんだけど,その新規 DHCP サーバが先に応答するという運に依存する部分があるのと,リースする IP アドレス空間をわけなきゃいけないので結局旧 DHCP サーバの設定を変える必要があるということで二の足を踏んでいた。

サブネット切って自分用ローカル環境でやるかなぁと思っていたところ,id:viver さんが Proxy DHCP という素敵なしくみを紹介なさっていた。

というわけで、PXEには3種類ある。

  1. 普通のDHCPのやりとりだけど、DHCPOFFERにPXEの拡張オプションが入っている(DHCPサーバーの設定の変更が必要)
  2. DHCPサーバーを動かしているホストでProxyDHCPサーバーを動かす(少しだけDHCPサーバーの設定の変更が必要)
  3. DHCPサーバーとは別のホストでProxyDHCPサーバーを動かす(DHCPサーバーの設定の変更が不要)
PXEには3種類ある - Blog by Sadayuki Furuhashi

1番目は普通の PXE としてもちいられる手段(dhcpd.confnext-serverfilename を書く方法)。2番目と3番目が Proxy DHCP というしくみ。Proxy という名前からすると DHCP シーケンスを proxy するのかなと思いきやそういうわけではなく,PXE にかかわるシーケンスだけ(通常の DHCP サーバと)別のサーバでまかなうという手法。これがそもそも PXE の規格で決まっているらしい。

2番目の方法は,同一ホストに DHCP サーバと Proxy DHCP サーバを共存させる*2方法。だから Proxy DHCP サーバは 4011 という DHCP とは別のポートであがることになる。

そして3番目の方法が,DHCP サーバと Proxy DHCP サーバを別のサーバで立てる方法。まさに今回のような状況のためのもの。Proxy DHCP サーバは DHCP サーバポート(67)と Proxy DHCP ポート(4011)両者に応答する必要が(仕様書にしたがって full spec に実装する場合)ある。


で,id:viver さんは Proxy DHCP を紹介なさるだけではなく,この3番目の Proxy DHCP サーバとして動く実装も作ってらっしゃった。それが pxe-pdhcp(⇒ PXEには3種類ある - Blog by Sadayuki Furuhashi)。

ということで,今回 CentOS 5.3 で pxe-pdhcp を使って PXE ブートをやってみた。

余談: Proxy DHCP サーバでポート 4011 の待ち受けは必須か

仕様書を読むと,3番目の Proxy DHCP でも 4011 ポートを使って PXE Client とやりとりをしなくてはいけないように読める。でも pxe-pdhcp ではそのようになっていない。

ほんとに大丈夫かいなと思って試してみるとうまくいく。で,ソースと仕様書を付き合わせて謎がとけた。

通常,(一般的な DHCP でも)DHCPDISCOVER(C) → DHCPOFFER(S) → DHCPREQUEST(C) → DHCPACK(S) のようなシーケンスをたどる。Proxy DHCP の場合,この DHCPREQUEST(C) 以降で 4011 ポートでやりとりする(ことに仕様書の上ではなっているようだ)。

ところが,仕様書 Table 2-1 PXE DHCP Options によると PXE_DISCOVERY_CONTROL の bit 3 を立てると,最初の DHCPOFFER にブートファイル名(たとえば pxelinux.0)を含めることができる。

なので,pxe-pdhcp は,DHCPOFFER に NBP ファイル名を含めて返し(この時点ではポート 67だ),その後はなにもしない。実際の IP アドレスの割当などは通常の DHCP サーバが REQUEST や ACK などのシーケンスを通じてやってくれる。

TFTP サーバのインストール

CentOS 5では(つまり RHEL 5 も; 以下 RHEL については略) tftp-server というパッケージが用意されている。

PXE を使うためには(PXELINUX で使うためには?)tftp-hpa*3 という実装を利用しなくてはいけない?したほうがよい?という話をどこかで読んだんだけど((たぶん pxeboot の過程ではなくその後のブートストラップ(SYSLINUX)の過程で tsize オプションが必要になるからかも。see PXE ブートメモ | oopsの日記 | スラド)),tftp-server で普通に動いたということは,こいつの実体は tftp-hpa かもしれない*4

$ sudo yum install tftp-server

CentOS だと tftpd は xinetd 経由で駆動するようになってる。そのへんの設定はあとで。

PXELINUX のセットアップ

元記事だと syslinux tar ball をとってきてビルドしてるけど,CentOS 5 だと syslinux パッケージがインストールされていれば(そしてまず間違いなくインストールされていると思う)そこに含まれている。

  • /usr/lib/syslinux/pxelinux.0

が,それ。

TFTP サーバで公開するファイルの準備

tftp-server のデフォルト設定は,/tftpboot/ というディレクトリ以下を公開するんで,それをそのまま利用する。まずは先ほどの pxelinux をコピーする。

# cd /tftpboot

# cp /usr/lib/syslinux/pxelinux.0 .

とりあえずの動作確認用に元記事と同じように現在動いているカーネルと initrd をコピーする。

# cp /boot/vmlinuz-`uname -r` .

# cp /boot/initrd-`uname -r` .

# chmod 644 initrd-`uname-r`

# ln -s vmlinuz-`uname -r` vmlinuz

# ln -s initrd-`uname -r` initrd.img

CentOS だと initrd のパーミッション0600 になっている(ため tftpd がアクセスできない)ことに注意。ここではまった。

ちなみに元記事にならって initrd.img という名前にしてるけど,ここを initrd という名前にしておくと,boot コマンドラインinitrd=initrd.img というオプションを指定する必要がなくなる(自動的に initrd というファイルを取得してくれる)。


PXELINUX 用の設定ファイルを書く。

# mkdir pxelinux.cfg

# vi pxelinux.cfg/default

default という名前にしておくと,最終的な fallback としてこいつを読んでくれる。

というのは,(下記の実行画面をみるとわかるけど)PXELINUX ブートローダは最初に MAC アドレスに基づく設定ファイルを取得しようとし,そのあとは DHCP で割り振られた IP アドレスに基づく設定ファイルを取得しようとし,それでもなければ default という名前のファイルを取得しようとするのだ。

なので,ぎっちぎちに静的割当で管理するのなら,各マシン用に設定ファイルを用意してもいい。

今回は IP は動的割当するので,とりあえず default ということで。

なお,全マシン用に共通の設定ファイルを使ったとしても,Linux を起動する場合は initrd (initramfs) に IP や MAC アドレスに基づく処理を記述しておけば,client によって挙動を変えることができる。そういう方針のほうが楽だと思う。


んで,設定内容は元記事と同じような感じで以下のとおり。

default mypxe
prompt 1
timeout 50

label mypxe
kernel vmlinuz
append initrd=initrd.img

これで,TFTP サーバで公開するディレクトリツリーは以下のようになった。

+ /tftpboot/
  - vmlinuz      (symlink to => vmlinuz-2.6.18-128.2.1.el5)
  - initrd.img   (symlink to => initrd-2.6.18-128.2.1.el5.img)
  - vmlinuz-2.6.18-128.2.1.el5
  - initrd-2.6.18-128.2.1.el5.img
  + pxelinux.cfg/
    - default

各種サーバの起動

あとはサーバ(pxe-pdhcp,tftpd)を起動するだけ。

と,そのまえに,CentOS だと iptablesDHCP や TFTP のポートが閉じられているので開けておく。system-config-securitylevel-tui で操作するのなら,Other ports のところに tftp:udp, bootps:udp を追加する(それぞれポート番号は 69, 67)。

tftpd の起動についてだが,CentOS の場合 xinetd 経由で駆動しているので,chkconfigtftp を on にしておいて(もちろん /etc/xinetd.d/tftp を手でいじってもいいけど),xinetd を再起動する。

$ sudo /sbin/chkconfig tftp on

$ sudo /sbin/service xinetd restart

で,pxe-pdhcp を起動。

$ sudo ./pxe-pdhcp -l 0.0.0.0 -b 255.255.255.255 -t 192.168.0.145 -d pxelinux.0

元記事だと -i eth0 のようにネットワークインタフェースを指定して起動しているけれど,これではわたしの環境ではうまくいかなかった*5Proxy DHCPによるネットワークブート - GeekFactory のように,Proxy DHCP daemon の listen address と broadcast address を指定してうまくいった。

また tftp サーバとして -t オプションで指定している 192.168.0.145 というのは,このマシンに割り振られているアドレス(ここで TFTP も提供しているからね)。当たり前だけど localhost ではうまく動作しない(PXE Client に通知するアドレスだから)。

PXE Client の起動

PXE ブートが可能なように BIOS 等で設定して起動すると PXE ブートする。

VMware Server(等)の場合,BIOS 画面で [ESC] キーを押して,Boot Menu から Network boot を選ぶと PXE ブートを試みてくれる(もちろん BIOS 設定で起動優先順位を変えてもいいけど)。

さきほどちらりと書いたけど,まず client の MAC アドレス(上記例では 00 0C 29 26 8F A9)に基づいたファイル名の PXELINUX の設定ファイル(01-00-0c-29-26-8f-a9 ……先頭の 01- はなんなんだろう)をまず読みにいく。

次に,この client に割り振られた IP アドレス(上記例では 192.168.0.146)を16進数で表記したもの(上記例では C0A88092)に基づいたファイル名を読みにいき,なければ順次サブネット(/4 単位で)さかのぼって探していってる。


さて。

PXELINUX の config で prompt を表示するように設定したので boot: ってでてる。で Enter キーを押すかタイムアウトまで待つと,ブートシーケンスが始まる。

んで,root ファイルシステムが見つからないので PANIC する((RedHat 系の場合,(Debian 系と違って?)汎用 initramfs を使うのではなく環境に応じて initramfs を構築する。その証拠に /dev/sda2 にレジュームイメージがみつからないといわれている。これは,起動に利用した initrd を構築したマシンでは /dev/sda2 が swap だったから。))。

あとはネットワークブート可能な initramfs を用意したりいろいろあるんだけど,とりあえずのテストなのでここまで。

memtest86+ の起動

というので終わるとあまりに実用的じゃないので,memtest86 系を PXE でブートできるようにしてみた。

つっても Memtest86+ - Advanced Memory Diagnostic Tool にある Pre-Compiled Bootable Binary (.gz) をとってきて,gunzip して /tftpboot/ 以下に memtest86plus などの名前で置き,pxelinux.cfg/default

label memtest86+
kernel memtest86plus

のように書くだけ。

+のつかない memtest86 のほうは USB key image を使えばいいのかなと思ってやったらうまくいかなかった。よくみてみたら,ダウンロードページの Linux source and binary package という tar ball を落として,そのなかの precomp.bin というファイルを同じように使えばいいみたい。


あとは,ハードディスクベンダのテストツールが動かせたら便利かなと思ったけど,たいてい DOS ベースなので試してないです。

ちらりと調べたら DOSPXE で起動するには

などの方法があるみたい。

入手性からいうと今だと後者のほうが試しやすいのかな。


と,いろいろ便利なツールを PXE ブート可能にしていくと地味なブートプロンプトじゃなく GRUB のメニューを使いたくなってくるけど,PXE GRUB はまだやってない*6。PXELINUX 単体でもメニューは出せるみたい(⇒ PXEでメニューを表示する。 - adsaria mood)。

*1:PXE用DHCPサーバの設定 - adsaria mood 参照

*2:この手法の場合,既存の DHCP サーバ側も DHCPOFFER に PXEClient というオプションを立てるよう改造する必要がある。じゃあ意味ないじゃんと思ったけど,DHCP サーバに PXE 関連のすべての機能を実装するよりは簡単に改造できるので,サーバベンダのために,このような手法が規定されているのではないかと思った。

*3:hpa というのは H. Peter Anvin の略で,この人は SYSLINUX の開発者でもある。

*4:RPM SPEC とか調べるのがめんどかったんで strings したら tftp-hpa 0.42 ってでたからそうみたい。

*5:ネットワークインタフェースを指定して起動すると,今回の例だと listen address が 192.168.0.145,ブロードキャストアドレスが 192.168.0.255 になる。しかし DHCPOFFER は 255.255.255.255 宛にブロードキャストされているんだと思う。これは 192.168.0.* で listen しても(少なくとも CentOS の場合)捕まえることができない。

*6:GRUB 1 系列だと PXELINUX より対応しているネットワークインタフェースが少ないという噂もあったし。