Cover V13, i07
jul2004.tar

Embedded Linux Router

Tom Erjavec

Embedding Linux to create a networking device has long been a desired project of mine. With the advent of many micro-Linux distributions, it has become an easy task that can be done by any Linux lover. My goal was a high-performance secure Internet gateway, so I built a PC/Linux device that could offer full speed on an Ethernet port and provide a firewalled connection to the Internet.

It would be easy to run just one of the Linux Router Project solutions off a floppy disk. But the 1.44 or 1.68 MB floppy space that most LRP solutions provided was not sufficient for the router software configuration I wanted. One possibility was to move the software to a hard disk or to burn the software image onto a CD and run the router off the CD drive. But I decided to go for a solution with no moving mechanical parts. I wanted a flash-disk solution without any drives, connected devices, or even a cooling fan in order to provide an "install-and-forget" and completely silent operation.

The goal of my project is sketched in Figure 1. The routing device must support NAT, DHCP, DNS, and packet filtering with stateful inspection. More than two network segments can be configured, thereby creating one or more demilitarized zones. Inbound NAT enables packet forwarding to virtually provide services on the router while they are really running on a machine in the demilitarized segment. All this and more (using additional LRP packages) is possible with an LRP distribution.

Hardware

The hardware I found suitable for my purpose was an older Cyrix MediaGX 233 set-top box, Allwell STB3036. It's a slim-line, small footprint PC with power consumption low enough to survive without a power-supply fan, and a processor slow enough not to need a cooling fan (Figures 2 and 3). The STB3036 is equipped with M-Systems' DiskOnChip (DoC) device providing 16 MB of solid-state disk space in a flash onboard, but it lacks both a floppy drive and a CD drive. The DoC module is situated in a corner of the motherboard, making it easy to extract and insert the module into the socket (Figure 4).

Software

My software selection was Jacques Nilo's and Eric Wolzak's LEAF/Bering, a derivative of Charles Steinkuehler's Dachstein, itself a derivative of Dave Cinege's original Linux Router Project. The underlying Linux is a dwarfed Debian distribution. I chose Bering because it included Tom Eastep's Shoreline Firewall, a handy configuration utility around iptables. Additionally, Jacques Nilo's archive offers a number of fine software packages that are compatible with Bering. The documentation that comes with Bering is very well written, and it is not difficult to set up a customized environment. The prefixed acronym LEAF (Linux Embedded Appliance Firewall) suggests the purpose itself.

The first obstacle I encountered was booting my hardware platform without a floppy drive from a Bering startup floppy disk. I didn't have an external floppy drive so I used my desktop PC instead. I disconnected the floppy data cable from my desktop PC's motherboard and connected it to the STB3036 motherboard. After powering desktop PC first and STB3036 second, it looked like a blood transfusion but it worked fine (Figure 5). STB3036 woke up in the micro-Linux environment of Bering. As a candidate for embedding, it is clear that Bering does not run off the boot media but rather generates a RAM disk in the system's memory, transfers all the software from the boot media into the RAM disk, and runs from there.

Once my black box with micro-Linux was running, it was still far from operational as a router. Because a micro-Linux kernel supports very few devices straight out of the box, it is necessary to provide all the drivers for the specific hardware being used. The kernel that comes with Bering 1.2 is 2.4.20 and is modular. Jacques Nilo provides a broad range of various modular device drivers in his repository:

http://leaf.sourceforge.net/devel/jnilo/bering/latest/modules/
To support my Ethernet interfaces, I used the drivers for RealTek and 3C905c-TX:

mii.o, 8193too.o and 3c59x.o
Looking ahead to the end of my project, I downloaded also the modules to support the DiskOnChip flash:

mtdcore.o, docecc.o, doc2000.o, docprobe.o and nftl.o
Bering also contains support for PPP, PPPoE, HDLC, and ASYNC communications, which were of no interest to me. So, I deleted these modules from the distribution floppy and replaced them with the ones I needed. If you need more modules than can fit on the distribution floppy, an alternative approach would be to provide support for the flash first, then boot off the flash (as described later on) and add the remaining modules manually by copying them from the mounted floppy disk(s) to the RAM-disk. Then, you could re-run the configuration procedure and save the new configuration back to the flash boot image.

I activated the modules with the insmode command manually to test whether everything worked. It did. The docprobe module revealed the segments of my flash memory, and ntfl module gave life to the /dev/nftla device. However, the flash was still unusable without partitions and a file system.

Configuring Modules

So far, all the work has been done manually. To make Bering set the customized environment automatically, the system must be configured. This can easily be done with lrcfg, the Bering configuration menu system. Modules can be added at two points in the micro-Linux file system. The modules that do not need to be active at the beginning of the boot procedure (e.g., Ethernet drivers) are placed in /lib/modules using the "Packages configuration -- modules" menu selection in lrcfg. However, the drivers that are necessary for reading from the boot device (e.g., flash memory drivers in my case) must be loaded prior to the boot procedure. These are placed in /boot/lib/modules using the "Packages configuration -- initrd" menu selection. When the flash image is saved, these will be put into the initial RAM disk for startup purposes.

Because Bering runs off the RAM disk, all the configuration changes done in RAM disk must be saved back to the target boot media before restarting the system. This can be done using the backup options in the lrcfg menu (Figure 6).

Configuring Services

The future services of the routing platform are defined and configured by adding software packages to the bare-bone routing platform. Many of them are already included in the distribution, such as:

  • IPtables packet filtering
  • Pump (DHCP)
  • Shorewall configuration tool for iptables
  • Logging utility
  • DNS cache

But there are some that may be added. I used the following additional packages:

  • libz.lrp
  • sftp.lrp
  • sshd.lrp
  • sshkey.lrp

These provided remote management through SSH, although a simple Web-based monitoring is provided with the initial system (Figure 7). Some additional services you may want to consider include:

  • A tiny FreeSWAN package for IPsec VPN tunneling
  • A tiny HTTP server (a question of security)
  • A tiny SMTP server (again, a question of security)

My selection of additional packages was too big to fit on the distribution floppy. I added them onto the RAM-disk file system after my machine was booting off the flash and then reconfigured the boot image.

Note that a .lrp package is nothing but a gzip archive. All LRP packages have a common structure and as long as they are compiled for the same kernel, they can be interchanged among various derivatives of the original LRP project. On Bering, I used some from Charles Steinkuehler's Dachstein and they worked perfectly well.

Besides the services you want to run, you must also acquire the packages needed for customizing the system. These will be used only once and, after the finished setup, they can be deleted from the system. These packages are:

  • fdisk.lrp
  • mkdosfs.lrp
  • syslinux.lrp

They will provide target disk partitioning, creation of the file system, and setting up the boot procedure, respectively.

The services can be configured individually through the lrcfg menu once they have been successfully installed in the RAM disk. The installation can be done manually by running the lrpkg command or automatically by defining the service in the syslinux.cfg file, as described in the next section.

I will not describe here how to configure the networking services, Shorewall firewall, and other individual packages. That process is very well described in the Bering documentation.

Starting Services

The system startup is provided by Peter Anvin's syslinux. It can boot Linux from DOS FAT-12 filesystem, which is used in LRP. To load a service from the target disk, the service package must be copied to the root of the filesystem and the service must be included in the LRP= parameter of the syslinux.cfg file. My line for loading packages is:

LRP=root,etc,local,modules,iptables,pump,keyboard,shorwall, 
ulogd,dnscache,weblet,libz,sshkey,sshd,sftp
After editing the syslinux.cfg file and saving the configuration changes, it's time to start the embedding. Note that the procedure described so far is sufficient to boot the final configuration from a floppy. This setup will be able to see the flash disk as a device, but the flash will still be empty.

Embedding

With flash modules in /boot/lib/modules, the system reset will bring up all software needed for accessing the flash in DoC. The first tasks are to create a partition table in the master boot record of the flash disk and to create a file system. The tools for this are installed with:

lrpkg -i fdisk.lrp
lrpkg -i mkdosfs.lrp
fdisk is used on a flash disk in the same way as on any hard drive:

fdisk /dev/nftla
A partition table is created in the MBR of the flash disk, then a new primary partition is created. Its partition type must be changed from Linux type 83 to type 01 (FAT-12). The active flag must be set for this partition and the table saved to the flash disk /dev/nftla.

Now a FAT-12 partition exists on the/dev/nftla1, but it is empty. A FAT-12 filesystem is created in it by running:

mkdosfs -F 12 /dev/nftla1
This makes the flash disk ready to use. It can be mounted to the root file system in the mountpoint /doc by:

mkdir /doc
mount -t msdos /dev/nftla1 /doc
The configuration that was created in the RAM disk and saved to the boot media (curently still the floppy disk) must now be transferred onto the flash. The floppy is mounted and then the files are copied:

mount -t msdos /dev/fd0u1680 /mnt
cp /mnt/* /doc
Effectively this transfers the contents of the floppy disk into the flash. The contents of the flash are almost ready, but it still needs some tweaking. Let's look at a complete syslinux.cfg file:

display syslinux.dpy
timeout 0
default linux initrd=initrd.lrp init=/linuxrc rw root=/dev/ram0 \
  boot=/dev/fd0u1680:msdos PKGPATH=/dev/fd0u1680
LRP=root,etc,local,modules,iptables,pump,keyboard,shorwall, \
  ulogd,dnscache,weblet,libz,sshkey,sshd,sftp
The pointers that refer to the floppy drive must be replaced by pointers to the flash disk:

boot=/dev/nftla1:msdos
PKGPATH=/dev/nftla1
Now the pointers are fine, but there is no bootstrap code in this partition. The syslinux package is used for that purpose. Syslinux version 1.62 never worked for me, so I used version 1.42, which worked fine. There are newer versions around but I had no need for them. To prepare the bootstrap code in the target partition, it must first be unmounted from the RAM disk:

umount /doc
syslinux -s /dev/nftla1
The last command created a ldlinux.sys file in the root of the target filesystem. It contains Step 3 of the bootstrap code, executed just after Step 2 of the bootstrap code in the boot record of the active partition in the flash, which runs after Step 1 bootstrap code in the MBR.

The big moment has arrived. We do one last check: the partition table is OK; the file system is OK; the bootstrap code should be fine; the modules configuration is OK; the packages are OK. Power down. Power up. Change the boot device order in BIOS from floppy drive to flash. Reset. The screen flickers after the BIOS test and then comes the infinite darkness...

Debugging the Bootstrap Procedure

When trying to determine what went wrong, I suspected syslinux. I tried three different releases without success. When all reasonable resources had been tried, nothing was left but a HEX editor. I zeroed the Master Boot Record of the flash, restarted the setup from the beginning for the fourth time, and took snapshots of the MBR with dd after each step:

dd if=/dev/nftla of=/mnt/<snapshot-name> count=1
After this procedure, I inspected the 512-byte snapshots one by one with a HEX editor. I found out that fdisk didn't produce the Step 1 bootstrap code in the MBR after saving the partition table. With no bootstrap code in MBR at boot time, the execution was never transferred to the active partition's boot record and that was the reason for the "infinite darkness" I experienced (Figure 8).

I looked around and found a 16-year-old floppy disk with MS-DOS 6.2. The floppy still worked (I am not sure about MS-DOS). Microsoft did implement a non-documented switch with their FDISK.COM to provide the Step 1 bootstrap code in the MBR by issuing the command:

FDISK /MBR
However, this command does not address any specific device and, as one might expect, the bootstrap code is written to the MBR of the first physical disk. I could not address my flash in this way so I had to do the procedure manually.

I made FDISK /MBR on a spare disk of another machine, but any other healthy disk with an MBR should be fine. Then I ripped the bootstrap code from the MBR off that hard drive by using:

dd if=/dev/hda of=/mnt/mbr.bin bs=512 count=1
I used a floppy disk as the transfer media and patched the bootstrap code over the first sector of my flash:

mount -t msdos /dev/fd0 /mnt
dd if=/mnt/mbr.bin of=/dev/nftla bs=512 count=1
Then I continued the normal setup procedure on the flash for the fifth time, starting with the creation of a new partition table in the patched flash MBR with fdisk. The rest is a replay of the previous section.

For those that don't keep old floppies around or don't want to dd MBRs of healthy (usually non-backuped) hard drives, I must add that, obviously, I did this the hard way. If I had thoroughly read the documentation of syslinux, I'd have known that Peter Anvin provided a generic MBR, including the assembly language source code that contains the Step 1 bootstrap code. However, the Bering step-by-step instructions keep this fact as a secret, and you must know the bootstrap procedure pretty well to locate the problem. I did not experiment with this generic MBR code since I trusted my patchwork was flawless.

This time the reboot didn't fail. In comparison to a floppy disk, the flash provided a lightning-fast bootstrap.

Performance Evaluation

I installed a commercial SOHO router and my embedded Linux router side-by-side to operate in the same environment. My evaluation test was feeding traffic in increments of 1 Mb/s on the internal side through the router to the external side. A probe measured the achieved throughput. The generated packets had the maximum size of 64 KB and were fragmented by the source machine to the largest acceptable framesize on Ethernet -- 1518 bytes. In real life, the packets would be smaller and the routers would be busier with NAT address translation on additional smaller-sized packets. Still, the measurement can give us a feeling for performance comparison.

Figure 9 shows the throughput graph for the commercial router. It was incrementally loaded with eight 1-Mb/s streams. In the beginning, the increments can be seen from the graph, but after the fourth increment (at 4 Mb/s), the linear response of the router is broken, the graph starts oscillating, and the router starts dropping IP packets. The packet loss went as high as 86% with router saturation reached at just over 4 Mb/s.

The situation is much different in Figure 10, which shows the response of the embedded Linux router. Note that the scales of the two graphs are different -- the graph of the commercial router scales to 7 Mb/s, while the scale of the Linux router graph is almost 10 times higher (60 Mb/s). The Linux router was incrementally loaded with 40 simultaneous streams of 1 Mb/s. The graph shows a nice linear response without any sign of saturation. At 42 Mb/s, ten times exceeding the threshold of the commercial router, the packet loss of the Linux router was 0% while the packet delay increased from 1 ms to 75 ms, which is still a quite acceptable response time.

Conclusion

An embedded LRP Linux device can be an appealing security gateway. This solid-state box with no moving parts and Linux hidden in a flash is an "install-and-forget" solution with automatic log rotation that needs very little or no maintenance. Superior performance, compared to commercial devices, and an availability of various configurable networking services make it ideal for an advanced SOHO user.

The Bering distribution, a flavor of LRP, is one of the more advanced LRP branches. However, Bering already has a descendant called Lince, developed by Juan Jesus Prieto. It includes a downsized Squid proxy server and Dansguardian Web content filtering package in the standard distribution. The sacrifice (or rather evolution) is that Lince no longer fits on a floppy but on a CD-ROM.

FreeSWAN IPsec VPN package is another logical choice for an embedded Linux router. But, it should be noted that 3-DES algorithm implemented in FreeSWAN drains the processor power significantly. Loaded with encrypted IPSec traffic, the performance of a system would be expected to drop by a factor of 10.

References

1. LEAF project (Bering, Dachstein, Lince, Oxygen, etc.) -- http://leaf.sourceforge.net

2. Tom Eastep's firewall project Shorewall -- http://www.shorewall.net

3. Repository of the Bering project -- http://sourceforge.net/project/showfiles.php?group_id=13751

4. Compiled modules for Bering, Linux kernel 2.4.20 -- http://leaf.sourceforge.net/devel/jnilo/bering/latest/modules/

5. Peter Anvin's Syslinux -- http://syslinux.zytor.com/

6. Repository of Syslinux releases -- http://www.kernel.org/pub/linux/utils/boot/syslinux/

7. Charles Steinkuehler's home page -- http://lrp.steinkuehler.net/

8. Original LRP homepage -- http://www.linuxrouter.org/

Tom Erjavec was awarded his M.Sc. from computer science at the University of Ljubljana, Slovenia. In the past, he was an assisting teacher at Faculty of computer science in Ljubljana. He then worked with IBM Slovenia as a software developer, with SRC as an electronic meeting systems manager. He co-founded a network integration company MIBO Integra, and is now a marketing director at Iskra Transmission, a microwave telecommunications equipment vendor. Linux remains his hobby.