Linux In A Small Box

For several years, my house router was an old PC with several PCI ethernet cards, running Debian lenny. It took up space, consumed much more power than the job really demanded, and was very noisy. So I wanted to clone the system onto some more appropriate platform.

My first candidate was a second hand Soekris net4501. I got a long way into setting this up before deciding to abandon it (see below for the reasons why), and switched instead to a Fabiatech FX5624. I completed the job using this system and it’s now in service.

The Soekris net4501

This has a 133MHz 486-like CPU and 64MB of RAM. It has three 10/100Mbit ethernet ports, making it ideal as a router. For storage, you can use a compact flash card. It has a serial port, but no VGA.

In appearance it is not especially exciting ☺

Cloning Debian onto the Soekris

I cloned the system onto a spare 2GB compact flash card connected via a card reader to the origin system. I allocated 1.5GB to / and the remaining 0.5GB to swap. Here’s what the fdisk output looks like:

   Disk /dev/sda: 2080 MB, 2080374784 bytes
128 heads, 32 sectors/track, 992 cylinders
Units = cylinders of 4096 * 512 = 2097152 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1   *           1         715     1464304   83  Linux
/dev/sda2             716         992      567296   82  Linux swap / Solaris

I used mkfs and mkswap to create a filesystem and swap partition. I’d hoped to do without swap but it turns out that the Soekris does not have enough RAM to run dpkg!

It’s convenient to identify filesystems by UUID, so that they can survive the vagaries of modern device enumeration, which doesn’t always give consistent results, and driver changes, which guarantee differing device names. To find out the UUID of an existing filesystem:

tune2fs -l /dev/sda1|grep UUID

Having created and formatted a root partition as ext3, I copied the original system onto it and chrooted into it to make further preparations for the change of hardware. It’s necessary to manually mount /proc and /sys inside the chroot.

I had an hdparm command left over from the old system. This was inappropriate for the new one and caused it to hang.

Kernel And Ramdisk

The Soekris uses a 486-class CPU so I installed the linux-image-486 metapackage to get the right kernel package, and removed the old -686 kernel. libc6-i686 went as well. (When I later switched to the Fabiatech, these steps had to be reversed.)

Rebuilding the initramfs on the Soekris was very slow (and the result very large) so I configured it to include only the modules absolutely necessary for booting. In /etc/initramfs-tools/initramfs.conf:

MODULES=list

...and then listed the required modules in /etc/initramfs-tools/modules:

ide_generic
ide_disk
ext3
natsemi
ide_core

natsemi is the network driver. The rest are to do with disk IO; ide_generic in particular is critical as the system will not detect the CF card without it!

After making these changes, to rebuild the initramfs:

update-initramfs -v -u

Linux Configuration

I edited /etc/udev/rules.d/70-persistent-net.rules to mention the new systems MAC addresses (helpfuly printed on the bottom of the unit). This ensures a predictable and consistent relationship between the device names and the physical ports. If you don’t know the MAC addresses in advance, just delete the existing settings and they will be filled in at boot time.

I updated /etc/fstab for the new system.

UUID=a074580f-dc9c-4d09-8133-8fdb05bf7365 / ext3 defaults,noatime,errors=remount-ro 0 1
/dev/hda2 none swap sw 0 0

I edited the virtual console lines (1-6) out of /etc/inittab and added a line for the serial console:

S0:2345:respawn:/sbin/getty -L 57600 ttyS0 vt100

(The Fabiatech has a faster serial port, so I used 115200 there. The same applies in other places below where the speed is set.)

Boot Loader

Legacy Grub works fine on the Soekris (I hear that LILO works fine too). I didn’t try Grub 2.

First it is necessary to install it on the CF card. In the chroot, /boot/grub/device.map should reflect the device name of the CF card, in my case /dev/sda but if you’re trying this at home, check.

(hd0)	/dev/sda

(Note that this will need to be changed later on.)

Then I installed Grub:

grub-install --no-floppy /dev/sda

To configure the kernel to use the serial port, I set kopt line in /boot/grub/menu.lst:

# kopt=root=/dev/hda1 ro console=ttyS0,57600n8 noreplace-paravirt

To clarify:

The console setting makes Linux use a serial console.

The noreplace-paravirt setting suppresses some paravirtualization support which does not run on the Soekris’s CPU. See #511703 and #515982. Without it the crash will look like this:

[    0.120007] Checking 'hlt' instruction... OK.
[    0.144009] BUG: unable to handle kernel NULL pointer dereference at 00000286
[    0.156009] IP: [<c010797d>] text_poke_early+0x41/0x52
[    0.164010] *pde = 00000000
[    0.172010] Oops: 0000 [#1]
[    0.172010] Modules linked in:
[    0.172010]
[    0.172010] Pid: 0, comm: swapper Not tainted (2.6.26-2-486 #1)
[    0.172010] EIP: 0060:[<c010797d>] EFLAGS: 00010286 CPU: 0
[    0.172010] EIP is at text_poke_early+0x41/0x52
[    0.172010] EAX: 00000286 EBX: 0000000a ECX: 00000000 EDX: 00000286
[    0.172010] ESI: c0363ee0 EDI: c010797f EBP: c0107975 ESP: c0363eb0
[    0.172010]  DS: 007b ES: 007b FS: 0000 GS: 0000 SS: 0068
[    0.172010] Process swapper (pid: 0, ti=c0362000 task=c033a320 task.ti=c0362000)
[    0.172010] Stack: 00000286 00000000 c036a62e c03ab534 0000000a c0363ee0 c0363ed6 c0107a71
[    0.172010]        c03b21bc 9d50c1ef 26b48d90 00000000 000000b6 00000000 c03ec868 00000046
[    0.172010]        00000046 c033e5e0 00000000 c0344d60 00000000 00000000 c0105dcc c0363fec
[    0.172010] Call Trace:
[    0.172010]  [<c036a62e>] native_init_IRQ+0x46/0x79
[    0.172010]  [<c0107a71>] apply_paravirt+0x81/0x91
[    0.172010]  [<c0105dcc>] do_IRQ+0x50/0x60
[    0.172010]  [<c0104763>] common_interrupt+0x23/0x30
[    0.172010]  [<c011c446>] vprintk+0x269/0x275
[    0.172010]  [<c012c1ef>] ktime_get+0xd/0x21
[    0.172010]  [<c0131619>] tick_nohz_stop_sched_tick+0x24f/0x259
[    0.172010]  [<c0105dcc>] do_IRQ+0x50/0x60
[    0.172010]  [<c0104763>] common_interrupt+0x23/0x30
[    0.172010]  [<c036b705>] alternative_instructions+0x23/0x3c
[    0.172010]  [<c036bf98>] check_bugs+0xd2/0xd4
[    0.172010]  [<c03649bc>] start_kernel+0x271/0x27e
[    0.172010]  =======================
[    0.172010] Code: 00 89 c2 fa 90 8d b4 26 00 00 00 00 90 89 c8 89 ef c1 e8 02 89 c1 f3 a5 89 d9 83 e1 03 74 02 f3 a4 89 d0 50 9d 90 8d b4 26 00 00 <00> 00 b8 01 00 00 00 0f a2 5a 89 e8 5b 5e 5f 5d c3 55 31 c9 57
[    0.172010] EIP: [<c010797d>] text_poke_early+0x41/0x52 SS:ESP 0068:c0363eb0
[    0.176011] ---[ end trace 4eaa2a86a8e2da22 ]---
[    0.180011] Kernel panic - not syncing: Attempted to kill the idle task!

The Soekris provides console emulation via the serial port but Grub hangs with this, until a serial console is attached. However Grub can instead write directly to the serial port bypassing this problem; I added the following lines to /boot/grub/menu.lst to achieve this:

serial --unit=0 --speed=57600
terminal serial

I ran update-grub and checked that the generated kernel list at the bottom of the file were sensible.

Communications

I used picocom to get a serial console the Soekris, with the following command:

picocom -f x -b 57600 /dev/ttyS0

Your favourite terminal program will doubtless work too.

Unit Configuration

> show

ConSpeed = 57600
ConLock = Enabled
ConMute = Disabled
BIOSentry = Enabled
PCIROMS = Enabled
PXEBoot = Disabled
FLASH = Primary
BootDelay = 5
FastBoot = Disabled
BootPartition = Disabled
BootDrive = 80 81 F0 FF
ShowPCI = Enabled
Reset = Hard
CpuSpeed = Default

Booting

I transferred the CF card to the Soekris and booted off it, with a serial terminal attached to detect any problems.

I checked edit /boot/grub/device.map again, to reflect that it’ll henceforth run on the Soekris rather than in a chroot:

(hd0)   /dev/hda

On the Fabiatech this is /dev/hdc.

It should not be necessary to re-install Grub, however.

Abandoning the Soekris

The difficulty with the -486 kernel left me worrying that kernel support for 486-class CPUs is going to get worse rather than better. Also, I found that although IP forwarding performance was adequate, I was annoyed by the slow speed of the machine for other operations.

As a result I bought a Fabiatech FX5624. This is a similar device but somewhat more powerful: 6 ethernet ports (two of them gigabit), a faster CPU and more RAM.

The Fabiatech FX5624

This machine has six ethernet ports, four of them 10/100M and two of them Gigabit ethernet. Like the Soekris, it is ideal for use as a router. It has two USB sockets, a VGA port, a combined PS/2 mouse/keyboard port and a serial port. It has a gig of RAM and a 600MHz Celeron CPU.

$ cat /proc/cpuinfo 
processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 9
model name	: Intel(R) Celeron(R) M processor          600MHz
stepping	: 5
cpu MHz		: 600.033
cache size	: 512 KB
fdiv_bug	: no
hlt_bug		: no
f00f_bug	: no
coma_bug	: no
fpu		: yes
fpu_exception	: yes
cpuid level	: 2
wp		: yes
flags		: fpu vme de pse tsc msr mce cx8 apic sep mtrr pge mca cmov pat clflush dts acpi mmx fxsr sse sse2 tm pbe up bts
bogomips	: 1201.99
clflush size	: 64
power management:

ide_generic works.

The Gigabit Ethernet ports use the r8169 driver:

[   11.679700] r8169 Gigabit Ethernet driver 2.2LK-NAPI loaded
[   11.690890] PCI: Setting latency timer of device 0000:01:00.0 to 64
[   11.691670] eth0: RTL8168c/8111c at 0xf8886000, 00:04:a7:05:ac:0b, XID 3c4000c0 IRQ 221
[   11.712004] r8169 Gigabit Ethernet driver 2.2LK-NAPI loaded
[   11.723174] PCI: Setting latency timer of device 0000:02:00.0 to 64
[   11.723946] eth1: RTL8168c/8111c at 0xf8890000, 00:04:a7:05:ac:0c, XID 3c4000c0 IRQ 220

The 10/100M ports use the 8139too driver:

[   14.614016] 8139too Fast Ethernet driver 0.9.28
[   14.627397] eth2: RealTek RTL8139 at 0xe800, 00:04:a7:08:af:b0, IRQ 16
[   14.640019] eth2:  Identified 8139 chip type 'RTL-8100B/8139D'
[   14.641368] eth3: RealTek RTL8139 at 0xe400, 00:04:a7:08:af:af, IRQ 17
[   14.653486] eth3:  Identified 8139 chip type 'RTL-8100B/8139D'
[   14.656005] eth4: RealTek RTL8139 at 0xe000, 00:04:a7:08:af:ae, IRQ 18
[   14.668017] eth4:  Identified 8139 chip type 'RTL-8100B/8139D'
[   14.669459] eth5: RealTek RTL8139 at 0xd800, 00:04:a7:08:af:ad, IRQ 19
[   14.682499] eth5:  Identified 8139 chip type 'RTL-8100B/8139D'

I think the corrugated part of the top may be a heatsink for the CPU.

This is what you see if you take the bottom of the case off (necessary to install the compact flash card or hard disk).

I’ve not attempted to get a look at the top half yet. Check back later for that and the rear.

Transitioning From The Soekris

Unlike the Soekris, this hardware can be attached to a screen and a keyboard as well as a serial terminal. Initially I used this to go into the BIOS to tell it to use 57600 bits/second instead of the default 9600 bits/second, to match the speed Grub and Linux use. The BIOS can talk to the serial port so you could probably do this that way, but it would be a bit slow.

Once I’d “found my feet” I set all the speeds to 115200.

Linux saw the compact flash card as /dev/hdc, so once I’d got a Grub menu up I pressed “e” and edited the kernel command line. If you don’t do this it will pause several minutes when seeking the root filesystem and then give you a rather restricted shell prompt.

Once it had booted I adjusted /etc/fstab and /boot/grub/menu.lst. I had to re-run grub-install --recheck --no-floppy /dev/hdc before update-grub would play nicely.

The Soekris demanded a 486-compatible kernel. This works on the Fabiatech too but I installed linux-image-686 instead as that is better optimized for the Fabiatech’s CPU. This also pulled in the -686 version of the Libc.

The noreplace-paravirt option discussed on the page about the Soekris is not required.

I’d commented out the virtual console entries in /etc/inittab because the Soekris had no screen or keyboard. I restored them.

I removed natsemi from /etc/initramfs-tools/modules and /etc/modules. The Fabiatech doesn’t use this driver.

Conclusions

Debian works well on both platforms, if you have adequate storage, and with the caveat on the Soekris about the kernel bug described above. At no point did I feel any need to use a distribution specifically targetted at small systems. (Although the Fabiatech isn’t really all that “small”, in comparison to the Soekris, although it’s well behind a modern desktop computer.)

The Fabiatech is probably more future-proof (as well as being substantially more powerful), though the Soekris clearly still has life in it yet if you’re a bit more patient than me. (And there are more recent Soekris models, too.)

Links

RJK | Contents