Embedded Linux with NAT support

 

作者: 許凱銘   最近更新日期:2003-7-10
附註:本文為自由文件,歡迎轉載,轉載不需與本人聯繫,但請註明出處。
 

 

1.    概要

2.開機過程簡述

3.KERNEL LOADER (SYSLINUX)

4.編選KERNEL

5.建立一個Boot Filesystem

6.建立一個root filesystem

6.1 概觀

6.2建立基本的工具程式---- busybox

6.3建立帳戶管理的工具程式---- tinylogin

6.4建立init ---sysvinit

6.5建立 bash shell 環境

6.6建立 etc 資料目錄

          6.6.1 建立組態設定檔/etc/inittab

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.6.4建立組態設定檔/etc/fstab

6.7 設定DNS功能於/etc/nsswitch.conf

6.7.1編輯 /etc/resolv.conf設定 DNS server

6.8安裝設備檔/dev

6.9 Runtime 函式庫/lib

7架構NAT server

8架構Web server

9.References

 

 簡介:

對於作業系統而言,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

 

 

 

1.    概要

 

 

我們實作一個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

 

 

3.KERNEL LOADER (SYSLINUX)

 

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

 

4.編選KERNEL

 

我們先介詔一個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。

 

5.建立一個Boot Filesystem

 

既然選擇用syslinux做為loader,也將 kernel Image做好,接下來就得做一個Boot Filesystem,我們將8mbCF卡分割成兩部份前1.5MB 做為BOOT Filesystem 格式為FAT12 後約6.5MB做為ROOT Filesystem 格式為ext2,您必須會使用LINUXFdisk 指令來操作,此外要讓CF卡能開機最重要的是

製作CFMBR (Master Boot Record )做作如下

下戴 syslinux 2.0以上的板本

你會發現裡頭有一個 mbr.bin 的檔案  接下來必須判斷你的CF卡接在ide1(hda[master]/hdb[slave]) 還是ide2(hdc[master]/hdd[slave])

我是接在ide2master所以是hdc,再來執行

#dd if = mbr.bin of = /dev/hdc

這樣就可以寫入mbr到你的CF CARD裡了

最後的工作如下:

kernel放入CF卡裡

安裝syslinux(#syslinux /dev/hdc1)

將寫好的syslinux.cfg boot.img放入BOOT Filesystem

 

6.建立一個root filesystem

造出 root filesystem 涉及選擇能讓系統正常運作所必備的檔案。在這一節中,我們將敘述如何建造一個 root filesystem 。就如同上面所說,我們有6.5MB的空間來建立root filesystem

 

6.1 概觀

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)

 

6.2建立基本的工具程式---- busybox

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

 

6.3建立帳戶管理的工具程式---- tinylogin

 

Tinylogin包括一組供工具程式,提供帳戶管理如登入、密碼更改、新增、更改或刪除帳戶及記錄。它的架構亦像Busybox一樣, 盡優化空間的佔用。不過,它的功能並沒有因此而減少,它同樣支援shadowSHA密碼、adduserdeluserloginsusecuretty等,同普通安裝的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

 

6.4建立init ---sysvinit

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支援下列指令

 

 

6.5建立 bash shell 環境

方法有兩種,若您的系統有支援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)

 

6.6建立 etc 資料目錄

 

下面將介詔如何建立etc 資料目錄(主要是組態檔的設定)

 

 

 

6.6.1 建立組態設定檔/etc/inittab

在我們初使化完大部份的程式之後接下來的工作也十分麻煩,我們有安裝了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

6.6.4建立組態設定檔/etc/fstab

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功能

 

 

6.8安裝設備檔/dev

您可以用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

 

6.9 Runtime 函式庫/lib

必須設定好你所須要的library,之前busybox,sysvinit,等所產生的指令執行檔都得再check清楚並把須要的library放入/lib

 

7架構NAT server

linux 2.2.X核心為基礎,必須安裝ipchains

我們下戴ipchains-1.3.9-bin.tar.gzbinary的板本,這將省去了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

 

 

8架構Web server

描述:

我們這個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才能解決,安裝各種軟体都是不容易的,許多的設定也都要小心,加上必須一直重複開機測試耗時且辛苦。多閱讀相關文件多測試才能成功。

 

 

 

9.References:

¨         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