OpenWRT on the Ubiquiti EdgeRouter X

Sun 17 April 2016 | tags: openwrt

The Ubiquiti EdgeRouter X running OpenWRT happily

Choosing the Ubiquiti EdgeRouter X

As I will be moving soon I will be needing a new router for managing my home network. There are hundreds of routers availble at various prices in many stores but I knew I wanted something beefier than most consumer routers and preferably run my favourite router firmware on it: OpenWRT. With that in mind, I researched a handful of candidates and decided on the Ubiquiti EdgeRouter X. It's a small 5-port gigabit router with no wireless support but sports a dualcore Mediatek MIPS processor and has both 256MB of RAM and NAND Flash. The inreased RAM and Flash size compared to most consumer routers would come in very handy with OpenWRT as it would allow me to install plenty of extra software packages later on, and allow me to use the storage for saving any logs or other files. The lack of WiFi support didn't bother me, this router will be mounted near my front door where the cable modem will reside and I would like my WiFi AP to have a somewhat more central location in the house anyway.

So, I had chosen for this EdgeRouter X, but I knew there was one catch: barely any information on getting OpenWRT on it seemed to be available. The OpenWRT techdata page listed some of the router's details but little else, and the OpenWRT device page was almost completely barren. It did however feature a picture of the internal serial port, which came in handy later. The most promising resource appeared to be a topic on the OpenWRT forums which showed that at least two people had gotten OpenWRT running on it, and that gave me just enough hope to give it a try myself.

A first look at EdgeOS

The Ubiquiti EdgeRouter X comes with the EdgeOS firmware by default. Contrary to the stock firmware on many consumer routers, this firmware is actually regarded as pretty decent and provides many features. Before flashing OpenWRT on the router, I had a little look around EdgeOS first.

After logging in on the web UI, the user is presented with some general live graphs on the first page and a status for all five ethernet ports. From here on many settings can be configured on either the main page or any of the other pages. I did notice however that my browser asked me if this website was allowed to run Flash. Why a router needs Flash on its web interface is beyond me.

SSH is enabled by default and you can log in with the same user credentials as for the web interface. Upon logging in, surprisingly enough I am greeted with a real bash shell. The linux version appears to be 3.10.14, and the presence of a /etc/debian_version file (containing "7.8") hints to me that the firmware is based on Debian. I wouldn't be surprised if it would be possible to use the official Debian repositories to install additional packages on this firmware.

As a last step before waving EdgeOS goodbye, I inspected /proc/mtd and used dd to make images of all the partitions, just in case. Here's the layout:

ubnt@ubnt:~$ cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00080000 00010000 "SPI_FLASH"
mtd1: 0ff80000 00020000 "ALL"
mtd2: 00080000 00020000 "Bootloader"
mtd3: 00060000 00020000 "Config"
mtd4: 00060000 00020000 "eeprom"
mtd5: 00300000 00020000 "Kernel"
mtd6: 00300000 00020000 "Kernel2"
mtd7: 0f7c0000 00020000 "RootFS"

I'm not entirely sure what the SPI_FLASH is used for, but the firmware resides on the NAND flash (recognisable by the different erasesize). The ALL partition covers the same memory as all the following partitions toghether. U-Boot and its configuration resides on mtd2 and mtd3 respectively. The eeprom partition probably contains some settings for the router hardware, though I can't be too sure. After that two kernels are present, the second one as a fallback in case of a bad upgrade or flash corruption. Finally, the last and largest partition is used for the RW root filesystem (ubifs).

Compiling the OpenWRT images

The forum topic that I mentioned in the introduction of this article included a post that referred to a patch submitted in November 2015 introducing support for this specific device. This patch would've been too recent to have made it into a stable release of OpenWRT yet, so this meant I was going to be running the trunk version. The techdata page links to a nightly built trunk image specifically for this device, but this image is a sysupgrade image. When you are still running the stock firmware, this image won't do. The router needs to already be running OpenWRT if you want to use the sysupgrade image. For the purpose of getting the router on OpenWRT in the first place, so-called factory images are used. Looking through the nightly built trunk images, there was a noticable lack of this factory image however. Time to compile my own.

I set up a new OpenWRT buildroot environment as per the instructions:

git clone https://git.openwrt.org/openwrt.git
cd openwrt
./scripts/feeds update -a
./scripts/feeds install -a
make menuconfig

At this point, you will be asked how you want your Linux kernel and rootfs to be configured. Initially, I chose Mediatek Ralink ARM as the Target System. About 24 hours later, I realised that that had been a mistake as I couldn't manage to get any images generated without a load of compilation errors. Confusingly enough, when compiling for a Mediatek platform, for Target System you should choose Ralink RT288x/RT3xxx. This in turn enables you to choose from various Mediatek subtargets, in the case of the Ubiquiti EdgeRouter X you choose MT7621 based boards. Having done that, there will be a Target Profile specifically for this router. Now this feels a lot more reassuring than my earlier option where I couldn't choose subtargets or a profile.

Having ran make -j3 V=s (verbose compilation with 3 workers) I went into bin/ramips and found an image for my router! But, it's the same sysupgrade image that was available online, I still don't have the factory image I was looking for. Some thinking and exploration of the options in make menuconfig later, I realised what I needed to do. The factory images are different from the sysupgrade images in that they combine the kernel with a filesystem toghether, this is also called initramfs. Under Target Images, select ramdisk and leave the compression on lzma as it is. When doing another compilation run now, you end up with the factory images in addition to the sysupgrade image.

Installing OpenWRT

Now I needed to find a way to actually get OpenWRT on the router. There are likely multiple approaches to accomplishing this, but I went with what I believed to be the path of least resistance. I spotted the router to have just two small screws and decided to remove these. After this, the casing opens right up without breaking any stickers and as such this shouldn't affect your warranty. Low and behold, the pin headers for a serial connection are easily spotted and better yet: they are already populated! I grabbed my Adafruit-style USB to serial converter cable and hooked it up as per the pinout described on the OpenWRT device page. I launched the screen utility, set the baudrate to 57600, and I was awarded with a working serial connection. I have not come across many devices where it was this easy to set serial up.

Hooking up a serial connection to the router

Powering on the router now it becomes apparent that it is using U-Boot as a bootloader for its Linux-based EdgeOS. The following output shows this, and also an interesting addition in the form of some custom pre-implemented boot procedures:

============================================
Ralink UBoot Version: 4.3.S.0
--------------------------------------------
ASIC MT7621A DualCore (MAC to MT7530 Mode)
DRAM_CONF_FROM: Auto-Detection
DRAM_TYPE: DDR3
DRAM bus: 16 bit
Xtal Mode=3 OCP Ratio=1/3
Flash component: NAND Flash
Date:Jan 27 2015  Time:17:52:09
============================================
icache: sets:256, ways:4, linesz:32 ,total:32768
dcache: sets:256, ways:4, linesz:32 ,total:32768

 ##### The CPU freq = 880 MHZ ####
 estimate memory size =256 Mbytes
#Reset_MT7530

Please choose the operation:
   1: Load system code to SDRAM via TFTP.
   2: Load system code then write to Flash via TFTP.
   3: Boot system code via Flash (default).
   4: Entr boot command line interface.
   7: Load Boot Loader code then write to Flash via Serial.
   9: Load Boot Loader code then write to Flash via TFTP.
default: 3

Option 4 presents you with a classical U-Boot prompt and allows you to fiddle with the environment and run any supported commands. I was curious about option 1 though. This option claims to use TFTP to load an image from the network into RAM and then boot that image accordingly, a perfect approach to trying out an image without having to make any changes to the data present on the Flash memory.

I placed the generated initramfs image (bin/ramips/openwrt-ramips-mt7621-ubnt-erx-initramfs-kernel.bin) in the directory that's hosted by the TFTP server on my LAN and connected the router's eth0 port to this LAN. I then proceeded to powercycle the router so I could try out the boot option of interest. My second attempt succeeded, pressing the number 1 before U-Boot has printed out its choices helps significantly. Now I was presented with a short wizard asking for the required connection and image details:

You choosed 1
                                                                                             0


1: System Load Linux to SDRAM via TFTP. 
 Please Input new ones /or Ctrl-C to discard
        Input device IP (172.16.3.212) ==:192.168.2.199
        Input server IP (172.16.3.210) ==:192.168.2.104
        Input Linux Kernel filename (vme50) ==:openwrt.bin

 netboot_common, argc= 3

 NetTxPacket = 0x8FFE55C0

 KSEG1ADDR(NetTxPacket) = 0xAFFE55C0

 NetLoop,call eth_halt !

 NetLoop,call eth_init ! 
Trying Eth0 (10/100-M)

 Waitting for RX_DMA_BUSY status Start... done


 ETH_STATE_ACTIVE!! 
TFTP from server 192.168.2.104; our IP address is 192.168.2.199
Filename 'openwrt.bin'.

 TIMEOUT_COUNT=10,Load address: 0x80a00000
Loading: checksum bad                     
checksum bad         
checksum bad
Got ARP REPLY, set server/gtwy eth addr (70:5a:b6:b4:24:a1)
Got it                                                     
#################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         #################################################################
         ##############                                                   
done                   
Bytes transferred = 2731102 (29ac5e hex)
NetBootFileXferSize= 0029ac5e           
..Erasing NAND Flash...      
ranand_erase: start:80000, len:20000 
.Writing to NAND Flash...            
done                     
Automatic boot of image at addr 0x80A00000 ...
## Booting image at 80a00000 ...              
   Image Name:   MIPS OpenWrt Linux-4.4.6
   Image Type:   MIPS Linux Kernel Image (lzma compressed)
   Data Size:    2731038 Bytes =  2.6 MB                  
   Load Address: 80001000               
   Entry Point:  80001000
   Verifying Checksum ... OK
   Uncompressing Kernel Image ... OK
No initrd                           
## Transferring control to Linux (at address 80001000) ...
## Giving linux memsize in MB, 256

Starting kernel ...

Perfect, everything worked as intended and the OpenWRT factory image started to boot! Before continuing to flash the sysupgrade image, I had a quick peek at /proc/mtd to find out what partition layout OpenWRT has decided on for itself. This layout mostly matched the one used by EdgeOS, with some names being different and the exclusion of the SPI Flash partition and the ALL partition. All in order, so I used wget on the router to retrieve the sysupgrade image that I hosted with python -m SimpleHTTPServer and stored it in /tmp. Following this I ran the sysupgrade tool:

root@OpenWrt:/tmp# sysupgrade -v /tmp/openwrt-ramips-mt7621-ubnt-erx-squashfs-sysupgrade.tar 
Cannot save config while running from ramdisk.
killall: watchdog: no process killed
Watchdog handover: fd=3
- watchdog -
killall: telnetd: no process killed
Sending TERM to remaining processes ... dnsmasq ubusd logd netifd odhcpd ntpd 
Sending KILL to remaining processes ... 
1+0 records in
1+0 records out
Unlocking kernel2 ...

Writing from <stdin> to kernel2 ...     
Volume ID 0, size 11 LEBs (1396736 bytes, 1.3 MiB), LEB size 126976 bytes (124.0 KiB), dynamic, name "rootfs", alignment 1
Set volume size to 244682752
Volume ID 1, size 1927 LEBs (244682752 bytes, 233.3 MiB), LEB size 126976 bytes (124.0 KiB), dynamic, name "rootfs_data", alignment 1
sysupgrade successful
[   81.060000] reboot: Restarting system

Success! The router continued to boot the default option 3 and this time round OpenWRT booted from Flash. Contrary to the initramfs image, the UBIFS on the Flash got mounted too now and this gives you a nice and spacious RW root overlay. Mission accomplished! Now remains one important task, and that is to update the OpenWRT wiki with the information I have found during this little excercise.

Resources

OpenWRT techdata page
OpenWRT device page
OpenWRT forum topic

social