Embedded Linux with NAT support
作者: 許凱銘 最近更新日期:2003-7-10
附註:本文為自由文件,歡迎轉載,轉載不需與本人聯繫,但請註明出處。
6.6.2 建立組態設定檔/etc/init.d/starthere script and /etc/init.d/rc.S
6.6.3 建立組態設定檔/etc/init.d/halt script and /etc/init.d/reboot script
6.7 設定DNS功能於/etc/nsswitch.conf
6.7.1編輯 /etc/resolv.conf設定 DNS server
簡介:
對於作業系統而言,Linux它有著理想的特性:高可靠性、極好的網路和多工支援,和低成本,更重要的是他的開放原始碼,讓使用者不用花大筆鈔票就能使用。因此除了節省支出成本之外,能更自由、更有彈性地根據自己的需要來修改系統、開發產品。嵌入式系統市場是Linux最重要的應用領域之一。舉凡PDA
Pocket PC 與IA產品等等都可以利用 Linux來完成。
但是在製作Embedded Linux都會面臨到要如何利用最少的系統資源,來建構一個特定嵌入式環境的問題,我們的方式包含有把Linux Kernel依所要執行的目的環境量身打造,建構一個符合該硬體平台的Linux Kernel,避免不必要的核心功能與驅動程式。並且利用動態函式庫來減少儲存空間。
目標 :
(1)認識linux 架構
(2)學習configure kernel
(3)學習linux網路功能
(4)精簡linux以符合特定功能
(5)加入web server以便利用brower控制系統
(6)學習利用NAT
我們實作一個Embedded
Linux,除了基本的指令外,還具備有網路功能,此外還有WebServer伺服器及NAT的功能,也提供您可以作簡單的防火牆的設定,我們成功將它放入一片8mb的CF卡裡,在一般pc裡只要將它開機並做簡單的IP設定,即可擁有NAT的功能,以下我們將介詔如何實作,但過程十分煩瑣,因為我們只利用現有的Free
Software,親手打造一個小型的作業系統。我們採用CF TO IDE MODOLE 來做為我們的開發環境,如下圖
2.開機過程簡述
在還沒有談論如可製作簡易 Floppy Linux 之前,首先要瞭解整個開機的過程。當一部電腦一打開電源時,電腦裡的 BIOS 就會找尋有無系統開機磁片,此時會有兩種狀況產生:第一種狀況就是找到系統開機磁片,此時就會從系統開機磁片中的第 0 磁區、第 0 磁柱載入可開機磁區;另一種狀況就是找不到系統開機磁片的話, BIOS 就會找尋硬碟的 MBR ( Master Boot Record ),並且執行記錄在 MBR 上的開機載入程式( Boot Loader )進行開機。(對CF卡而言必須自己安裝MBR)
不管是從軟碟開機也好,還是從硬碟開機也罷,首先整個作業系統的 loader (就 Linux 來講就是 LILO 『 LInux LOader 』)會載入 Linux Kernel ,而 Kernel 一起動的第一件事就是進入保護模式( protected mode ),所有的硬體交由 Kernel 來控制,擺 脫 BIOS 的牽絆。(我們之後將利用SYSLINUX來做為LOADER)
一旦 Kernel 載入完畢之後,開始初始化系統所有硬體設備。當所有的硬體初始化完成之後,接著系統將嘗試掛載( mount ) root filesystem 。Root filesystem 就是被掛上當作” / ”目錄的 filesystem 。Kernel 必須知道從哪裡可以找到 root filesystem ( PS
一般系統磁碟片的 root filesystem 會被製作成以 ramdisk 執行方式的影像檔【 image 】),否則系統就會停止運作( halt )。
當 root filesystem 成功 的載之後,就會去執行 init 這個程式,init 就會開始檢查 /etc/inittab ,找出該檔中標明 sysinit 這一行,並執行該行的 script ,在 redhat 上為 rc.sysinit ,而 rc.sysinit 會進行系統的初始化動作,在這裡我打算不介紹這支 script 有興趣可以參考 redhat 上的 rc.sysinit 。
當 rc.sysinit 執行完畢之後,控制權立即轉回到 init 的手中,接下來馬上進入預設 runlevel 。若內定的 runlevel 為 3 的話, init 就執行 /sbin/mingetty 啟動 virtual console 並且以 : ” login :”提示讓使用者登入,完成開機。登入後系統會提供一個 shell 給使用者,就可以使用 Linux 。若 runlevel 為 5 的話,則在開啟 virtual console 之後,init 會再執行 xdm 啟動 X window system ,讓使用者以 xdm 界面登入。
因此Linux 開機的過程可以說是
BIOS ---->Loader ( LILO, SYSLINUX )----> Kernel ---->Init ---->Shell
Kernel loader 的任務在將核心影像移動到記憶体內,我們選擇用SYSLINUX使用syslinux 比起其它的Loader 如(LILO,grub)步驟簡單,而且功能完整。許多Embedded
System 皆使用它來當成kernel loader,至於如何使用有點類似LILO,欲更深入了解可參考Syslinux
網站 http://syslinux.zytor.com/
以下是我們的設定
#檔名syslinux.cfg
display boot.msg ß歡迎畫面
timeout 20 ß等待時間
prompt 1
default Kernel_Load
label Kernel_Load
kernel vmlinuz ßLinux Kernel名稱
append root=/dev/hdc2 init=/sbin/init ßinit 及 root File System
我們先介詔一個configure kernel的範例
建議進入Linux 視窗下比較好做
第一次製作:
#make xconfig會產生下面的視窗
(請選擇你要的功能再離開)
#make dep
#make zImage或make bzImage(若核心大於640K的話)<--壓縮
再次製作:
#make mrproper
#make xconfig
#make clean
#make dep
#make zImage或make bzImage(若核心大於640K的話)<--壓縮
Kernel的Image檔會在 /usr/src/linux-2.4.18-14(根據你的電腦而定)/arch/i386/boot 裡面//以red hat 8.0為例
選擇kernel是個必須要小心的,你有可能隨便勾選而產生錯誤,我們最後產生兩個相容性較好的kernel這兩個kernel能滿們足對網路的須求且大小適中,我們在很多平台上測試都可以順利執行
我們分別用mandrake 8.0 kernel 板本(2.4.19)支援ip_table
及 red hat 6.2 kernel 板本(2.2) 支援ip_chains
其中red hat 6.2 大小只有六百多K。
既然選擇用syslinux做為loader,也將 kernel Image做好,接下來就得做一個Boot Filesystem,我們將8mb的CF卡分割成兩部份前1.5MB 做為BOOT Filesystem 格式為FAT12 後約6.5MB做為ROOT Filesystem 格式為ext2,您必須會使用LINUX的Fdisk 指令來操作,此外要讓CF卡能開機最重要的是
製作CF的MBR (Master Boot Record )做作如下
下戴 syslinux 要2.0以上的板本
你會發現裡頭有一個 mbr.bin 的檔案 接下來必須判斷你的CF卡接在ide1(hda[master]/hdb[slave]) 還是ide2(hdc[master]/hdd[slave])
我是接在ide2的master所以是hdc,再來執行
#dd if = mbr.bin of = /dev/hdc
這樣就可以寫入mbr到你的CF CARD裡了
最後的工作如下:
將kernel放入CF卡裡
安裝syslinux(#syslinux /dev/hdc1)
將寫好的syslinux.cfg boot.img放入BOOT Filesystem
造出 root filesystem 涉及選擇能讓系統正常運作所必備的檔案。在這一節中,我們將敘述如何建造一個 root filesystem 。就如同上面所說,我們有6.5MB的空間來建立root filesystem
root filesystem 必須包含支援完整 Linux 系統運作所需的每一個項目。為了能夠達成這個目的,我們必須包括能讓 Linux 系統運作我們所要的須求:
基本的目錄: /dev, /proc, /bin, /etc, /lib, /usr, /tmp, /usr, /sbin,…
工具程式: sh, ls, cp, mv, etc.,
組態設定檔: rc, inittab, fstab, etc.,
設備檔: /dev/hd*, /dev/tty*, /dev/fd0, etc.,
Runtime 函式庫以提供工具程式所使用之基本功能 (functions) 。
BusyBox提供了一組基本的Linux指令。傳統上,我們在Linux使用者環境中所執行的指令都是許多個別的執行檔,不過這會產生一個問題就是這些指令所存在的執行檔,其實有許多的功能是我們所不常使用或是有部分的程式碼是可以重複利用的。而BusyBox這個免費的工具程式,就是為了解決這個問題所產生了,它把許多的Linux指令整合在同一個執行檔當中,並且針對這些執行檔提供充分的功能,讓使用者幾乎可以只利用BusyBox便完成一個實用的使用者環境,在Embedded System中常用這套工具但並非所有的指令它都有所支援,這次我採用了busybox-0.60.3來設計,很高興地,目前的板本支援了ifconfig 及 route指令,這對我們來說省去了很多的麻煩,為了使它們所佔的檔案空間較小我們在編譯此工具時做了以下的設定
vi Config.h (設定須要的功能將它們開啟)
vi Makefile 將DOSTATIC設為flase
# If you want a static binary, turn this on.
DOSTATIC = false
Make
Make PREFIX=/xxx install
之後會有 /bin /sbin /usr三個資料匣
在/bin 支援下列指令
ash cp dumpkmap gunzip ln mount ps stty uname busybox cpio echo gzip ls msh pwd sync usleep cat date false hostname mkdir mt rm tar vi chgrp dd fdflush hush mknod mv rmdir touch zcat chmod df getopt kill mktemp pidof sed true
chown dmesg grep lash more ping sleep umount
在/sbin支援下列指令
adjtimex ifconfig losetup mkswap reboot swapon
freeramdisk insmod lsmod modprobe rmmod syslogd
fsck.minix klogd makedevs pivot_root route update
halt loadkmap mkfs minix poweroff swapoff watchdog
在/usr/bin支援下列指令
deallocvt find loadfont rdate tee uniq whoami ar dirname free logger readlink telnet unix2dos xargs basename dos2unix head logname renice test uptime yes chvt dpkg hostid md5sum reset tftp uudecode clear dpkg-deb id mkfifo rpm2cpio time uuencode cmp du killall nc setkeycodes tr wc cut env length nslookup sort traceroute wget dc expr loadacm printf tail tty which
在/usr/sbin/ 支援下列指令
chroot dutmp fbset
Tinylogin包括一組供工具程式,提供帳戶管理如登入、密碼更改、新增、更改或刪除帳戶及記錄。它的架構亦像Busybox一樣, 盡優化空間的佔用。不過,它的功能並沒有因此而減少,它同樣支援shadow和SHA密碼、adduser、deluser、login、su及securetty等,同普通安裝的Linux沒有太大的分別。
可參考網頁http://tinylogin.busybox.net
和busybox 一樣
vi Config.h (設定須要的功能將它們開啟)
vi Makefile 將DOSTATIC設為flase
Make
Make PREFIX=/xxx install
在/bin 支援下列指令
addgroup adduser login su tinylogin
在/sbin 支援下列指令
getty sulogin
在/usr/sbin 支援下列指令
passwd vlock
sysvinit 能提供你系統上最基本的功能,它包含init program 它是當kernel 戴入完成後第一個您所要執行的程式,Init 之後能控制 startup, running, and shutdown等程序,此外還有其它的功能可到網上查詢。
cd src
Make
Make ROOT=/xxx install
在/bin 支援下列指令
pidof
在/sbin支援下列指令
halt init killall5 poweroff reboot runlevel shutdown sulogin telinit
在/usr/bin支援下列指令
halt init killall5 poweroff reboot runlevel shutdown sulogin telinit
在/usr/sbin支援下列指令
方法有兩種,若您的系統有支援bash,直接copy至您embedded system /bin目錄下即可,但必須將相依的library 一併copy至您embedded system /lib 目錄下,若您的系統不支援bash,或者您欲最小化bash shell的大小,你可以下戴source 並自行編譯
./configure --host=i386 ; make bash (沒有最小化)
./configure -host=i386 -enable-minimal-configure; make bash (最小化)
copy 相依的library 是件麻煩的工作,您可以利用 ldd 指令來幫您加速進行。
最後再做它的link如下
ln -sh bash sh
strip bash (減少size)
下面將介詔如何建立etc 資料目錄(主要是組態檔的設定)
在我們初使化完大部份的程式之後接下來的工作也十分麻煩,我們有安裝了sysvinit,就同上面所說第一個執行的程即是/sbin/init 這個程式將會去讀取
/etc/inittab, 這個 inittab 中對於各個
runlevel 要跑哪些 rc 或 spawn 必須做清楚的設定
以下是我們所做的設定
#檔名 /etc/inittab
# inittab setting
# default runlevel.
id:2:initdefault:
# first except in emergency (-b) mode.
si::sysinit:/etc/init.d/rc.S ß之後會去執行此一shell script
# single-user mode.
~~:S:wait:/sbin/sulogin
# 後面的 0~6 參數表示要跑該 runlevel 所應跑的設定 script.
# Runlevel 0 is halt.
# Runlevel 1 is single-user.
# Runlevels 2-5 are multi-user.
# Runlevel 6 is reboot.
l0:0:wait:/etc/init.d/halt
l2:2:wait:/etc/init.d/starthere ß /etc/init.d/starthere待會會執行此
shell script
#l3:3:wait:/etc/init.d/starthere
#l4:4:wait:/etc/init.d/starthere
#l5:5:wait:/etc/init.d/starthere
l6:6:wait:/etc/init.d/reboot
# CTRL-ALT-DEL pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -r now ß按下CTRL-ALT-DEL
# Action on special keypress (ALT-UpArrow).
#kb::kbrequest:/bin/echo "Keyboard Request--edit /etc/inittab to let this work."
# /sbin/mingetty invocations for runlevels.
1:2345:respawn:/sbin/getty 38400 tty1
2:2345:respawn:/sbin/getty 38400 tty2
3:2345:respawn:/sbin/getty 38400 tty3
4:2345:respawn:/sbin/getty 38400 tty4
5:2345:respawn:/sbin/getty 38400 tty5
6:2345:respawn:/sbin/getty 38400 tty6
7:2345:respawn:/sbin/getty 38400 tty7
8:2345:respawn:/sbin/getty 38400 tty8
9:2345:respawn:/sbin/getty 38400 tty9
#S1:2345:respawn:/sbin/getty 38400 ttyS1
#S2:2345:respawn:/sbin/getty 38400 ttyS2
下面我們要講到的是 /etc/init.d/starthere 這個 script 應該做些
什麼, 才是我們要的。
6.6.2 建立組態設定檔/etc/init.d/starthere script and /etc/init.d/rc.S
在starthere l script 裡我們將設定我們網路卡的ip 及戴入modules ,你得設定你的網路ip 等資訊在/etc/sysconfig/network裡方便在開完機後設定好網路功能,
而rc.S此一script 主要用途在mount 你的根目錄
#!/bin/sh
#戴入module
# Load modules in /etc/modules
for module in `cat /etc/modules`; do
/sbin/insmod /lib/modules/"$module"
done
#我們將network 設定在/etc/sysconfig/network 裡
# Configuring and starting network
#
ONBOOT=`grep ONBOOT /etc/sysconfig/network | sed 's/ONBOOT=//'`
if [ "${ONBOOT}" = yes ]; then
IPADDR=`grep IPADDR /etc/sysconfig/network | sed 's/IPADDR=//'`
NETMASK=`grep NETMASK /etc/sysconfig/network | sed 's/NETMASK=//'`
BROADCAST=`grep BROADCAST /etc/sysconfig/network | sed 's/BROADCAST=//'`
MTU=`grep MTU /etc/sysconfig/network | sed 's/MTU=//'`
GATEWAY=`grep GATEWAY /etc/sysconfig/network | sed 's/GATEWAY=//'`
/sbin/ifconfig lo 127.0.0.1 && echo -n
"lo
"
/sbin/ifconfig eth0 ${IPADDR} \
netmask ${NETMASK} \
broadcast ${BROADCAST} \
mtu ${MTU}
/sbin/route add default gw ${GATEWAY}
fi
#
# Setting host name
#
HOSTNAME=`/bin/hostname`
if [ -z "$HOSTNAME" -o "$HOSTNAME" = "(none)" ]; then
HOSTNAME=Embedded Linux
fi
/bin/hostname ${HOSTNAME}
rc.S此一script 主要用途在mount 你的根目錄
#!/bin/sh
#
#
# Re-mount root filesystem in read/write mode.
#
/bin/mount -a
/bin/mount -n -o remount r,w / ß允許讀寫
#
# Setting Host name
#
hostname -F /etc/sysconfig/hostname
6.6.3 建立組態設定檔/etc/init.d/halt script and /etc/init.d/reboot script
主要是關機和重新開機的設定不再多敘
#檔名/etc/init.d/halt
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
halt -w
umount -a
mount -n -o remount ro /
halt -d -f -i -p
#檔名/etc/init.d/reboot
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
halt -w
umount -a
mount -n -o remount ro /
reboot -d -f -i
proc /proc proc defaults 0 0
6.7 設定DNS功能於/etc/nsswitch.conf
passwd: compat
group: compat
shadow: compat
hosts: dns ß這行必須要加入
6.7.1編輯 /etc/resolv.conf設定 DNS server
nameserver 163.28.112.1
必須將相依的/lib/libnss_dns.* 相關的library COPY 至你的embedded system /lib目錄裡,支援DNS功能
您可以用mknod指令來自己製作你要的設備檔或利用copy -a 的方式來複製你要的設備檔下面是我們做的/dev目錄
console hda4 hdb5 hdc6 hdd7 loop6 ram0 tty urandom vcs9 vcsa9
core hda5 hdb6 hdc7 hdd8 loop7 ram1 tty0 vcs vcsa zero
fd0 hda6 hdb7 hdc8 hdd9 mem ram2 tty1 vcs0 vcsa0
fd1 hda7 hdb8 hdc9 initctl null ram3 tty2 vcs1 vcsa1
fd2 hda8 hdb9 hdd kmem port ram4 tty3 vcs2 vcsa2
fd3 hda9 hdc hdd1 loop0 pts ram5 tty4 vcs3 vcsa3
full hdb hdc1 hdd2 loop1 ptys0 ram6 tty5 vcs4 vcsa4
hda hdb1 hdc2 hdd3 loop2 ptys1 ram7 tty6 vcs5 vcsa5
hda1 hdb2 hdc3 hdd4 loop3 ptys2 ram8 tty7 vcs6 vcsa6
hda2 hdb3 hdc4 hdd5 loop4 ptysa ram9 tty8 vcs7 vcsa7
hda3 hdb4 hdc5 hdd6 loop5 ram random tty9 vcs8 vcsa8
必須設定好你所須要的library,之前busybox,sysvinit,等所產生的指令執行檔都得再check清楚並把須要的library放入/lib裡
linux 2.2.X核心為基礎,必須安裝ipchains
我們下戴ipchains-1.3.9-bin.tar.gz是binary的板本,這將省去了Runtime library的麻煩
Linux 2.4.x核心為基礎,必須安裝好iptable
我們找不到iptable binary的板本,所以必須將所須要的library 複製到 /lib 底下,之後我們以一張網路卡來實做 NAT
(eth0 :實体ip,eth0:0虛擬ip(192.168.0.253)如下圖
我們分別設計兩個不同板本的kerner (2.2 , 2.4.18)
可分別設定如下
ipchains---- ipchains -A forward -s 192.168.0.0/24 -j MASQ
iptables ---- iptables -t nat -A POSTROUTING -o eth0 -s 192.168.0.0/24 -j MASQUERADE
描述:
我們這個project為了要方便使用者可以設定系統的環境與IP,所以需要加入web server,以便讓使用者可以利用網頁來設定系統,因為比較有名的web server - Apache 會使用到比較多的空間 , 所以我們使用V. Ziemann ziemann@tsl.uu.se 所寫的WWWserver-0.1 , 這個tiny web server是利用tcl (Tool Command Language)所寫出來(/usr/bin/tclsh ) , 他支援了 GET 、POST 與CGI。
使用方法 :
只要把 WWWserver.tcl執行檔放到網頁目錄(ServerRoot),然後執行 WWWserver.tcl port#
瀏覽網頁的方式
http://domainname:port#/abcd.html
我們自己利用tcl寫了下圖的網頁,讓使用者可以configure ethernet
此設定網頁會去修改 /etc/sysconfig/network ,然後會把剛剛設定的結果寫入
以下是寫入/etc/sysconfig/network的結果
ONBOOT=yes
IPADDR=140.116.82.78
NETMASK=255.255.255.0
BROADCAST=140.116.82.255
MTU=1500
GATEWAY=140.116.82.253
遇到的困難:
在設計boot filesystem 時,首先得解決如何讓CF卡能正當開機,即安裝mbr的問題,最常見的問題就是做好的kernel無法正常啟動,所以在config kernel時必須注意你所勾選的選項是你所須要的,所以最好了解各個選項的功能再勾選,再者,很有可能你所做的kernel相容性的問題,很有可能在別台電腦無法啟動,再者,驅動模組也是必須要小心選擇。
在設計root filesystem時,所遇到的問題就更多了,其中runtime library 的問題最麻煩,必須反覆測試才能把問題解決,而之前更有DNS server 設定的問題,必須看許多menu才能解決,安裝各種軟体都是不容易的,許多的設定也都要小心,加上必須一直重複開機測試耗時且辛苦。多閱讀相關文件多測試才能成功。
¨ Pocket_Linux :
¨ Busybox : http://www.busybox.net/
¨ HOWTO:The Linux Bootdisk
¨ Linux Router Project (LRP) :
http://www.mn-linux.org/meetings/pastnotes/lrp_intro.html
¨
uClinux : http://www.uclinux.org/description/
¨ Floppy based Linux : http://eastlrc.valencia.cc.fl.us/faculty/linux/floppy_linux.html
¨ Linux 2.4 NAT HOWTO