Wednesday, May 7, 2014

Java on OpenWRT

A friend wanted to run a Java program on a consumer OpenWRT router for a demo.  Some tips from that experience:

(1) Finding a suitable router.  Typical consumer routers have very little RAM and flash, something like 16MB RAM / 8MB flash - they might be able to run a simple OpenWRT image, but a Java VM is out of the question.  Low-end routers like recent releases of the Linksys WRT-54G might have something more like 8MB RAM / 2MB flash.

The Netgear WNDR3800 has a useful amount of RAM (128MB) and a large-ish amount of flash (16MB).  The Atheros processor is reasonable as well (a 680MHz AR7161, which has a MIPS core).  It is also a member of the WNDR3700 family which has a very active OpenWRT community.  (Note that recent WNDR3700 releases, like the WNDR3700v4, don't run OpenWRT very well.  You probably need a WNDR3700v1, WNDR3700v2, or WNDR3800.  I got a couple of refurb WNDR3800s for ~$40 each - they've been EOL'd.)

(2) Finding a suitable OpenWRT image.  hnyman's IPv6 build of OpenWRT is actively maintained for WNDR3700/3800, and is easy to install/run.  Just download from his website and install it using the Netgear firmware upload screen.   Later updates can be installed from the OpenWRT firmware upload screen.

(3) Finding a lightweight Java VM that runs on MIPS.  If you Google for "java openwrt" there are a lot of forum postings lamenting the lack of a working JVM for OpenWRT.  However, jamvm (an actively maintained lightweight JVM) has had an OpenWRT ipkg right there in the OpenWRT opkg repository for a couple of years.

(4) Finding enough flash space to install jamvm.  If you try to opkg install jamvm, you find that GNU Classpath is required but immediately tries to use ~60MB of flash.  The internal flash partition used to store new files (as a read/write /overlay filesystem) is only ~10MB.

However, since there's a working USB storage driver for WNDR3700, you can easily take an old USB flash drive, plug it into the USB 2.0 port, format it as ext4, and fiddle /etc/config/fstab so that it mounts the USB flash drive as its read/write /overlay filesystem (instead of the initially-configured internal partition).  Now you have GBs of space instead of MBs.

(5) Running jamvm.  You probably need to use something like "jamvm -Xms64M -Xmx64M" to limit its RAM usage.  You may need "jamvm -cp foo.jar com.bar" instead of "jamvm foo.jar com.bar"but at this point HelloWorld.class built on your desktop should run fine.

(6) Finding and building an updated jamvm package.   The ipkg may not work for what you want to do - as of this writing, the jamvm ipkg being built by OpenWRT's buildbots is based on an arbitrary Git snapshot from late 2011 (4617da717ecb05654ea5bb9572338061106a414d) and seems to have some concurrency bugs that HelloWorld doesn't uncover.  

I'm not going to get into the details of how to build and install OpenWRT packages, but it is  not too hard to figure out from hnyman's distro, since he has shared his personal update-and-build harness.  If you want to compare behavior to current OpenJDK/IcedTea releases on Debian (either 6 or 7), you can start with OpenJDK's Git snapshot of jamvm from late 2012 (0972452d441544f7dd29c55d64f1ce3a5db90d82).  That way you can try "identical" releases on your x86 desktop and on your MIPS OpenWRT router.  (Since they are different platforms they are not actually identical, of course...)

You can update and rebuild into the existing /Openwrt/feeds/packages/.../jamvm - select it for build and install it.  GNU Classpath should be fine as it hasn't been updated since 0.98 in 2009 :-/