Ubuntu - Basic routing using systemd-networkd

This page shows how to enable router functionality on Ubuntu 16.04 using systemd-networkd. Similarly to instructions given in Ubuntu - initial network configuration, the kernel (we used kernel version 4.4.52) has to be compiled with several NETFILTER/IPTABLES/NAT features. Make sure that the toolchain and the toolchain path are set up as shown in Build from source - Toolchain.

Building the kernel

First head to where you have downloaded your kernel when following Build from source - Kernel and fetch & rebase your repository to make sure you have the latest updates. Now set the necessary environment variables and create a default .config file using the default values from arch/$ARCH/configs/${PLATFORM}_defconfig (in this case from arch/arm64/configs/mvebu_v8_lsp_defconfig):

espressobin@buildserver:~/kernel/4.4.52$ export ARCH=arm64
espressobin@buildserver:~/kernel/4.4.52$ export CROSS_COMPILE=aarch64-linux-gnu-
espressobin@buildserver:~/kernel/4.4.52$ make mvebu_v8_lsp_defconfig

There are two methods of enabling NETFILTER/IPTABLES/NAT options.

Downloading pre-configured .config file

.config file is located in the top of your kernel source tree and it contains kernel configuration. This file can be configured manually or via menuconfig, make xconfig, make XXX defconfig, make oldconfig and similar make XXXconfig targets in the Linux kernel.

The quickest method of achieving a .config file with afore-mentioned options enabled is to replace the file with a .config that has all these options already enabled. The .config files with NETFILTER/IPTABLES/NAT features enabled can be downloaded here:

Make sure to backup your existing .config file with:

espressobin@buildserver:~/kernel/4.4.52$ cp .config .config_old

before replacing it with the .config you have downloaded on the link above:

espressobin@buildserver:~/kernel/4.4.52$ cp /path_to_downloaded_config/ubuntu_systemd-networkd.config .config

If using this method, skip to Starting the build & transferring files section.

Manually selecting the options via menuconfig

Instead of replacing .config files you can also launch make menuconfig where you will manually need to select needed options:

espressobin@buildserver:~/kernel/4.4.52$ make menuconfig

Here we will search for (open search prompt by typing / and search string under Symbol) and select the following options:

Type  : boolean
Prompt: Network packet filtering framework
      -> Networking support (NET [=y])
(1)     -> Networking options  
   Defined at net/Kconfig:109
   Depends on: NET [=y]

By hitting the number on the left side of the option (in this case (1)) we are redirected to the location of this option:

       [ ] Timestamping in PHY devices
       [*] Network packet filtering framework (Netfilter)  --->
       < > The DCCP Protocol  ----

Hit Space to select the highlighted package (the option will be built-in when * is shown beside it). Use this method to select all options below.

  • 2) IP_NF_IPTABLES (build it as module)
Symbol: IP_NF_IPTABLES [=m]}
Type : tristate
Prompt: IP tables support (required for filtering/masq/NAT)


Symbol: NF_CONNTRACK [=y]
Type  : tristate
Prompt: Netfilter connection tracking support


Symbol: NF_CONNTRACK_IPV4 [=y]
Type  : tristate
Prompt: IPv4 connection tracking support (required for NAT)


  • 5) NF_NAT_IPV4
Symbol: NF_NAT_IPV4 [=y]
Type : tristate
Prompt: IPv4 NAT


Type  : tristate
Prompt: IPv4 masquerade support


  • 7) IP_NF_NAT (build as module)
Symbol: IP_NF_NAT [=m]
Type  : tristate
Prompt: iptables NAT support


  • 8) IP_NF_TARGET_MASQUERADE (build as module)
Type  : tristate
Prompt: MASQUERADE target support


  • 8) IP_NF_FILTER (build as module)
Symbol: IP_NF_FILTER [=m]
Type  : tristate
Prompt: Packet filtering

Save your configuration and exit the menuconfig

Starting the build & transferring files

Start the build with:

espressobin@buildserver:~/kernel/4.4.52$ make -j4

Now we need to transfer the new kernel image and dtb file to a microSD card or USB stick containing the desired Ubuntu file system. In the example below we mounted our microSD card to /mnt/sdcard and transferred the kernel image and dtb file to the boot directory:

espressobin@buildserver:~/kernel/4.4.52$ sudo cp arch/arm64/boot/Image /mnt/sdcard/boot/
espressobin@buildserver:~/kernel/4.4.52$ sudo cp arch/arm64/boot/dts/marvell/armada-3720-community.dtb /mnt/sdcard/boot/

We also need to install the generated kernel modules:

espressobin@buildserver:~/kernel/4.4.52$ sudo make ARCH=arm64 modules_install INSTALL_MOD_PATH=/mnt/sdcard/

In the command above, mnt/sdcard/ is the root of the file system on your removable media.

Unmount the SD card and boot from the SD card or USB stick as shown in Boot from MicroSD card/USB stick - Ubuntu.

Once the board has booted, follow the steps in the section below to configure routing.

Installing necessary packages

Now that Ubuntu has booted successfully, we will first enable Internet connection in order to download packages necessary for routing. Connect one end of an Ethernet cable into the WAN port on ESPRESSObin and the other to your router. In the console issue:

root@localhost:~# ifconfig eth0 up
root@localhost:~# dhclient wan

Open the /etc/apt/sources.list file and there add the universe repository:

root@localhost:~# vim /etc/apt/sources.list
#append universe to the first line
deb http://ports.ubuntu.com/ubuntu-ports/ xenial main universe

This repository is needed to download the dnsmasq package which is recommended to use with network managers other than Ubuntu's Network Manager. Save your changes and exit the editor. Now update and install the necessary packages:

root@localhost:~# apt-get update
root@localhost:~# apt-get install bridge-utils
root@localhost:~# apt-get install samba
root@localhost:~# apt-get install dnsmasq
root@localhost:~# apt-get install iptables
root@localhost:~# apt-get install libpam-systemd
root@localhost:~# apt-get install iptables-dev


Network configuration

Now on to creating the required network files and a virtual network device file for our bridge. This setup is similar to the default network configuration present when booting Arch Linux, as shown in Boot from MicroSD card/USB stick - ArchLinux.


root@localhost:~# cat /etc/systemd/network/br0.netdev


root@localhost:~# cat /etc/systemd/network/br0.network



root@localhost:~# cat /etc/systemd/network/eth0.network


root@localhost:~# cat /etc/systemd/network/lan.network



root@localhost:~# cat /etc/systemd/network/wan.network


Now make a backup of the default dnsmasq.conf configuration file and create a new file:

root@localhost:~# mv /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
root@localhost:~# vim /etc/dnsmasq.conf

and in there paste the following:


Now disable Ubuntu's default networking service and enable systemd-networkd:

root@localhost:~# systemctl disable networking
root@localhost:~# systemctl enable systemd-networkd

In the [Unit] section of the /lib/systemd/system/dnsmasq.service file append the following options for the bridge interface to be brought up before dnsmasq:

root@localhost:~# vim /lib/systemd/system/dnsmasq.service

Save your changes and exit the editor. Now set the iptable rule to start routing:

root@localhost:~# iptables -t nat -A POSTROUTING -o wan -j MASQUERADE

To preserve iptables rules upon reboot, first install the iptables-persistent package:

root@localhost:~# apt-get install iptables-persistent

followed by running:

root@localhost:~# netfilter-persistent save
root@localhost:~# netfilter-persistent reload

The rules will be saved to /etc/iptables/rules.v4. Finally, reboot the ESPRESSObin board, which should now act as a gateway between your laptop and Internet.