Mount BeagleBoard Root Filesystem over NFS via USB

This page explains how to bridge the usb0 device to eth0 on your Linux host, enabling your Linux host to act as a hub for your BeagleBoard and connecting it to the outside world. As an additional reference, the following article is good at explaining how to create a typical Ethernet bridge on a Linux machine with two Ethernet cards:

Linux Journal: Kernel Korner - Linux as an Ethernet Bridge

Before starting, make sure you have the "bridge-utils" package installed on your Linux host. This gives you the "brctl" command, which you need for creating and using an Ethernet bridge.

Step 1: Create an Ethernet Bridge from usb0 to eth0 on your Linux Host
The main difference between the scenario in the Linux Journal article mentioned above and the BeagleBoard is that we're creating a bridge from usb0 to eth0 instead of from eth1 to eth0. Also, we have to deal with the fact that "usb0" doesn't exist as a device on our Linux host except when the USB Gadget support is running on the connected Beagleboard, which isn't the case when we're first booting the Linux host.

My Linux host is running Fedora Core 10. I'm sure some of the following network configuration steps are specific to Fedora, but they can probably be easily adapted to other Linux distributions. On Fedora, I edited the network scripts "/etc/sysconfig/network-scripts/ifcfg-eth0" and "/etc/sysconfig/network-scripts/ifcfg-usb0" by hand to make sure those interfaces had no IP or gateway settings, and that they were not controlled by the Fedora network manager by setting NM_CONTROLLED=no.

Contents of /etc/sysconfig/network-scripts/ifcfg-eth0:

DEVICE=eth0 ONBOOT=no BOOTPROTO=none TYPE=Ethernet USERCTL=no PEERDNS=yes IPV6INIT=no NM_CONTROLLED=no

Contents of /etc/sysconfig/network-scripts/ifcfg-usb0:

DEVICE=usb0 ONBOOT=no BOOTPROTO=none TYPE=Ethernet USERCTL=no IPV6INIT=no NM_CONTROLLED=no PEERDNS=yes

Next, I created a new script "/etc/sysconfig/network-scripts/ifcfg-br0" that is going to be the "bridge" interface that connects both usb0 and eth0 to the outside world. This script looks a lot like what "ifcfg-eth0" used to look like.

Contents of /etc/sysconfig/network-scripts/ifcfg-br0:

DEVICE=br0 ONBOOT=no SEARCH="dmlab"                # Replace with your search domains BOOTPROTO=none NETMASK=255.255.255.0         # Replace with your subnet's netmask IPADDR=192.168.198.1          # Replace with your Linux host's IP address USERCTL=no PEERDNS=yes IPV6INIT=no GATEWAY=192.168.198.254       # Replace with your subnet's gateway TYPE=Ethernet DNS1=192.168.198.1 DOMAIN='dmlab'                # Replace with your Linux host's domain(s) NM_CONTROLLED=no Next, I created following init script and placed it in /etc/init.d/br0</tt>.
 * 1) Ethernet Bridge

Contents of /etc/init.d/br0</tt>:


 * 1) !/bin/bash

. /etc/rc.d/init.d/functions
 * 1) Source function library.

RETVAL=0

start {  /usr/sbin/brctl addbr br0 /usr/sbin/brctl addif br0 eth0 /sbin/ifup eth0 /sbin/ifup br0 return 0; }
 * 1) Check if all what named needs running

stop { /sbin/ifdown br0 /sbin/ifdown eth0 /usr/sbin/brctl delbr br0 }

restart { stop start }

case "$1" in	start)		start		;;	stop) stop ;;	restart)		restart		;;	*) echo $"Usage: $0 {start|stop|restart}" exit 3 esac
 * 1) See how we were called.

exit $RETVAL

I set the br0 init script to run during bootup by making the following symbolic link:

ln -s /etc/init.d/br0 /etc/rc5.d/S91br0

My system typically runs at runlevel 5 (hence rc5.d), and "S91" on my system runs after the networking scripts, but before critical services like dns, named, dhcp, samba, etc, which need the interface to be up when starting.

The br0 script manually brings up eth0 and br0, which is why it is important that these interfaces are not controlled by Fedora's network manager.

After re-booting the Linux host (without a BeagleBoard attached), the result of "ifconfig" should list "br0", "eth0", and "lo", and if you execute "sudo brctl show" it should list eth0 as being a member of the bridge.

$ ifconfig

br0      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx inet addr:192.168.198.1 Bcast:192.168.198.255  Mask:255.255.255.0 inet6 addr: fe80::21a:a0ff:feec:79f1/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500  Metric:1 RX packets:3875507 errors:0 dropped:0 overruns:0 frame:0 TX packets:3351392 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:2798652354 (2.6 GiB) TX bytes:977920512 (932.6 MiB)

eth0     Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx inet6 addr: fe80::21a:a0ff:feec:79f1/64 Scope:Link UP BROADCAST RUNNING PROMISC MULTICAST MTU:1500  Metric:1 RX packets:2015574 errors:0 dropped:0 overruns:0 frame:0 TX packets:3411988 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:1780819388 (1.6 GiB) TX bytes:972140276 (927.1 MiB) Interrupt:16

lo       Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436  Metric:1 RX packets:236666 errors:0 dropped:0 overruns:0 frame:0 TX packets:236666 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:317726283 (303.0 MiB) TX bytes:317726283 (303.0 MiB) $ sudo brctl show

bridge name    bridge id               STP enabled     interfaces br0            8000.001aa0ec79f1       no              eth0

You should be able to access the external network the same as before on your Linux host at this point.

Step 2: Booting the BeagleBoard
The next step is to boot the BeagleBoard with kernel parameters that tell it to mount its root file system over NFS. Here are the U-Boot settings I used to boot the kernel from an SD card, then boot the rootfs over NFS:

setenv bootargs 'console=ttyS2,115200n8 noinitrd rw ip=192.168.198.24::255.255.255.0 root=/dev/nfs nfsroot=192.168.198.1:/opt/dmsw/OE_BEAGLE_rootfs,nolock,rsize=1024,wsize=1024,rootdelay=2' setenv bootcmd 'mmcinit;fatload mmc 0 80300000 uImage;bootm 80300000'

In the above parameters, replace the following with settings for your network:

While the BeagleBoard kernel is booting, the usb0 device will show up on the Linux host. Run "ifconfig" a few times, and when "usb0" is listed, run the following command:

$ sudo brctl addif br0 usb0

This will add "usb0" to the Ethernet bridge, and the Linux host will now act as a hub for the Beagleboard. The Beagleboard will now continue to boot, but the weird thing is I didn't see any of the kernel boot messages scroll by while it's starting up. However, when it's done the "Angstrom" prompt comes up on the serial normally.

If you execute "sudo brctl show" after the BeagleBoard is done booting, it should now should both eth0 and usb0 being on the bridge:

$ sudo brctl show

bridge name    bridge id               STP enabled     interfaces br0            8000.001aa0ec79f1       no              eth0 usb0

Step 3: Accessing the Outside World from the BeagleBoard
You might want to make sure that any firewall software like iptables is disabled on the Linux host, or at least make sure the firewall settings allow the Linux host to act as a hub for your BeagleBoard. Otherwise, the BeagleBoard will not be able to see the outside world.

On the BeagleBoard, modify "/etc/network/interfaces</tt>", and configure the settings for "usb0".

Contents of BeagleBoard's /etc/network/interfaces</tt>:

iface usb0 inet static address 192.168.198.24  # Replace with BeagleBoard's IP Address netmask 255.255.255.0   # Replace with your subnet mask network 192.168.198.0   # Replace with your network address gateway 192.168.198.254 # Replace with your subnet gateway

Also, edit the /etc/resolve.conf</tt> on the BeagleBoard to point to your DNS server. Here are my settings:

Contents of BeagleBoard's /etc/resolve.conf</tt>: search dmlab                    # Replace with your domain search path nameserver 192.168.198.1        # Replace with your DNS server

Note that my linux host (192.168.198.1) is running a DNS server. If yours isn't, don't use your Linux host IP here -- set this to the DNS server that your Linux host is using.

Finally, bring up the usb0 interface on the BeagleBoard:

$ ifup usb0

You should now be up and connected as if your beagle board was on the network at the same level as the linux host.

$ ping some.machine.com

PING some.machine.com (192.94.93.21): 56 data bytes 64 bytes from 192.94.93.21: seq=0 ttl=247 time=18.005 ms                       64 bytes from 192.94.93.21: seq=1 ttl=247 time=10.254 ms                        ...

Automatically add usb0 to br0
Create /etc/udev/rules.d/52-add-net-usb-to-br.rules</tt> which adds usb0 to the bridge br0.

SUBSYSTEM=="usb", INTERFACE=="usb*", RUN+="/usr/sbin/brctl addif br0 usb0"

Tested under Ubuntu Linux 9.04 host. Unplug the USB cable, run sudo brctl show</tt>, then plug the cable and run sudo brctl show</tt> again to verify it was added.

Future Considerations

 * Make the udev script aware of the actual interface name (usbX).