So, I recently obtained a Linksys 1900AC router. While it is a powerul router, it really lacks some features I like to see on my router. As a OS X user it would have been nice to see Time Machine support but alas there is nothing. I bought it because there was an implicit promise that you can put OpenWRT on it.
Turns on only with the most recent OpenWRT version is officially supported. I tried version 15.05 RC2 and added TimeMachine support only to see the router degrade my network performance after one week. It actually bothered my roommate so much that she disconnected the “blue box” and put the “beige” box back. Thanks Netflix!
Well, so my overpriced router is standing in the corner without seeing actually usage. But now, 15.05, code name “Chaos Calmer” has officially been released. Hopefully they fixed my performance issues.
Time to give OpenWRT another go but this time by compiling it from source!
Going down the wrong route
Well, I was lying. We are actually not going to compile OpenWRT on OS X, even if the official wiki wants you to believe that is actually possible.
The one piece of information they are mising is that in order to compile OpenWRT you need a file sensitive file system! Which im guessing 99,9% of OS X users don’t have as it is not the default. Now I guess you could create a disk image with a file sensitive HFS file system, but let’s try something else.
Let’s not pollute the main system with dependencies you just need to make your outer work. For this kind of things Docker is amazing and its finally (kind of) working on OS X.
Installing Docker
Unfortunately Docker can’t run natively on OS X, but at least it runs “seamlessly” using a daemon on a virtual machine. I quote “seamlessly” because I had my fair share of troubles of making it work.
Let’s install VirtualBox and Docker
brew cask install virtualbox
brew install docker
brew install docker-machine
docker-machine create --driver virtualbox dev
It will prompt you to set your environment so that docker knows on which machine it should execute. I am running the fish shell, so it prompted me to
eval (docker-machine env dev)
Now you should have a running machine named dev
.
You can
# list your machines
docker-machine ls
# start `dev` machine
docker-machine start dev
# stop `dev` machine
docker-machine stop dev
# reread the instructions on how to set up you shell for `dev` machine
docker-machine env dev
Running the container
Now that Docker is up and running we can create the Docker image.
I’m not the first person coming up with the idea of using a Docker image for compiling OpenWRT. In fact George Jiglau create one and Andreas Kohn forked it and based it on OpenWRT 15.05.
mkdir -p ~/Docker/openwrt
cd ~/Docker/openwrt
wget https://raw.githubusercontent.com/ankon/docker-openwrt-buildroot/f67c9dbc3821766ef30d94acbf124a1eb86c94f6/Dockerfile
docker build .
It will create the Docker image. Run
docker images
REPOSITORY TAG ID CREATED
<none> <none> 6728bc817ad9 1 minute ago
And it should list your newly created image. Mine has the ID 6728bc817ad9
Preparing source code
So now we have our Docker image ready to compile OpenWRT. Let’s get to it.
# Take the id from the prvious step
docker run -i -t 6728bc817ad9 /bin/bash
# we need to compile as a non-root user, the image had "openwrt" user
su openwrt
cd ~/openwrt
# pull latest changes
git pull
Configure base system
It’s a good idea to not fiddle arround with too much option but to just go with the defaults and just setup the target system and see if everything compiles.
Run make menuconfig
and set the target system.
For the Linksys 1900 AC v1
- the
Target System
inmake menuconfig
should be set to “Marvell Armada XP/370” and - the
Target Profile
inmake menuconfig
should be set to “Linksys WRT1900AC (Mamba)”
Run make defconfig
Build it for the first time
# call make and enable console logging with V=s
make V=s
And now the wait begins. I’m serious. Get some coffee, do laundry, watch a movie. Your mileage may vary but it took arround 2 hours until everything was compiled.
Save your base image
What a glorious day. Everything compiled successfully. Let’s save that state of the image, so we can get back to this at a later stage and save us a lot of hassle in the future.
Let’s find that image
docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
da36d1d9481b 6728bc817ad9 "/bin/bash" 20 minutes ago Up 20 minutes grave_car
Commit changes to the container:
sudo docker commit da36d1d9481b openwrt
It feels good to have save that work, doesn’t it?
Add a webinterface
Especially because now we mess with the packages we want to integrate in our OpenWRT distribution.
While I love me some terminal, I think it is really nice to have a web interface to configure some of the basic stuff. So let’s add it, shall we?
he webinterface is called is called LuCI. It is not in the default set of packages and is supported in a separate “feed”.
# Update your feeds
cd ~/openwrt
./scripts/feeds update -a
# Make LuCI available as a package
./scripts/feeds install luci
If you now open make menuconfig
. You can add it to installation.
For good measure I throw in a make
here, to see if still everything compiles.
Add shairport-sync
Now that we have a webinterface, we try something more experimental
I’m basically following the steps from shairport-sync-for-openwrt. I opted to get bleeding edge and use the development branch, which supports shairport 2.4.
# Update your feeds
cd ~/openwrt
./scripts/feeds update -a
# Create shairport package
cd ~/openwrt/packages
git clone https://github.com/mikebrady/shairport-sync-for-openwrt.git
cd shairport-sync-for-openwrt
git checkout development
# Install packages in base system
cd ~/openwrt
./scripts/feeds install libavahi alsa-lib libdaemon libpopt libsoxr libconfig
Now do make menuconfig
and
- select
Sound > shairport-sync
. I made sure its not selected as a module but built in. - select
Kernel Modules > Sound Support > kmod-sound-core
andkmod-usb-audio
Let’s compile with make
.
Fetch the image
After hours of downloading and compiling things, the image is finally ready! .
All we have do is getting it onto the router. But first let’s get it onto the host machine. As my router is already running OpenWRT, I actually just need the upgrade package.
# fetch your container id with `docker ps -l`, in case you forgot
# mine is da36d1d9481b
# copy the sysupgrade
docker cp f9be3e8e90e5:/home/openwrt/openwrt/bin/mvebu/openwrt-mvebu-armada-xp-linksys-mamba-squashfs-sysupgrade.tar .
Flash the router
Now connect to your router with an Ethernet cable (you really don’t want to flash your device over WiFi).
open 192.168.1.1
Luckily my old installation also was running LuCI, which offers a interface for uploading a system upgrade.I just quickly deselect the box to keep my settings (I wanted to start fresh).
I upload the image and stare at my monitor for a minute.
Basic configuration
And what a relieve; after a tiny eternity I’m greeted with a login screen for my router with a warning that there is no password for root
. I went ahead and set one.
To configure the rest of the services you need SSH access. Add your public SSH key by
cat .ssh/id_rsa.pub | pbcopy
and pasting it into the Dropbear input field. You can restrict SSH access to certain interfaces such as Ethernet cable.
Shairport
Now that we have ssh access we can configure shairport-sync.
ssh 192.168.1.1
touch /etc/shairport-sync.conf
vim /etc/shairport-sync.conf
I added a very minimal configuration
general = {
name = "Living Room";
};
alsa = {
output_device = "hw:0";
};
The documentation states that one should specify the mixer, but I haven’t figured out a way how to get this information for my USB sound card and as the sound and response time was good enough for my taste I left it for another time. It might just mean to install alsamixer
to read that information.
Resume
It was a lot easier than I thought. Yes, I spent almost an entire day making this work, but at least one hour was fighting with Docker and VirtualBox and almost 4 hours were just spent on waiting for the compilation. If I would try it again, I might want to tewak the settings for the virtual machine, and giving it a bit more power before the actual compilation phase. Another idea is to spin up a server from a Cloud service and do the compilation there.