How to configure networking using systemd in Yocto Project

Introduction

This tutorial will guide you through configuring networking in Yocto using systemd-networkd. This is only one of the possible network management utilities available in Yocto. Other utilities may be documented in other tutorials.

This will use a Raspberry Pi 3 platform so that we can demonstrate both wired and wireless networking.

Prerequisites

To follow this tutorial, you will need:

We also recommend:

  • UART Console Cable: This allows you to view the console logs of the device using a USB-UART connection to your PC. See this link for more details. To enable the UART in your build, add the following to your local.conf file:
ENABLE_UART = "1"

Step 1

Enable systemd in your Yocto configuration by adding the following to your local.conf file:

# Enable systemd
DISTRO_FEATURES_append = " systemd "
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_init_manager = "systemd"
VIRTUAL-RUNTIME_initscripts = ""

Step 2

To be able to proceed with this tutorial we first must create a custom layer that will contain any custom modifications or additions. Please note that the tutorials on this site will re-use this layer and if you have already created this structure by following another tutorial you can skip this step.

Create a new layer called meta-stargazer using the bitbake-layers helper application:

bitbake-layers create-layer ../sources/meta-stargazer

This will create a basic structure in meta-stargazer directory:

../sources/meta-stargazer/
├── conf
│   └── layer.conf
├── COPYING.MIT
├── README
└── recipes-example
    └── example
        └── example_0.1.bb

3 directories, 4 files

Include the layer in our Yocto Project environment:

bitbake-layers add-layer ../sources/meta-stargazer

Step 3

Create a custom bbappend file for the systemd recipe.

mkdir -p ../sources/meta-stargazer/recipes-core/systemd
cat > ../sources/meta-stargazer/recipes-core/systemd/systemd_%.bbappend <<EOF
PACKAGECONFIG_append = " networkd resolved"
EOF

This will enable the appropriate configurations of systemd. These may be enabled by default depending on which branch of Yocto you are using, however explicitly setting them here ensures a known state.

Step 4

Create a recipe append for the systemd-conf recipe that contains networking configuration files.

mkdir -p ../sources/meta-stargazer/recipes-core/systemd-conf/files
cat > ../sources/meta-stargazer/recipes-core/systemd-conf/systemd-conf_%.bbappend <<EOF
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"

SRC_URI += " \
    file://eth.network \
    file://en.network \
    file://wlan.network \
"

FILES_${PN} += " \
    ${sysconfdir}/systemd/network/eth.network \
    ${sysconfdir}/systemd/network/en.network \
    ${sysconfdir}/systemd/network/wlan.network \
"

do_install_append() {
    install -d ${D}${sysconfdir}/systemd/network
    install -m 0644 ${WORKDIR}/eth.network ${D}${sysconfdir}/systemd/network
    install -m 0644 ${WORKDIR}/en.network ${D}${sysconfdir}/systemd/network
    install -m 0644 ${WORKDIR}/wlan.network ${D}${sysconfdir}/systemd/network
}
EOF

This sets up configurations for any device named by the Linux kernel starting with en, eth, wlan, which should cover most situations. The default setting here is to use DHCP.

Create the eth.network, en.network, and wlan.network files as follows:

eth.network

cat >../sources/meta-stargazer/recipes-core/systemd-conf/files/eth.network <<EOF
[Match]
Name=eth*
KernelCommandLine=!nfsroot

[Network]
DHCP=v4

[DHCPv4]
UseHostname=false
EOF

en.network

cat >../sources/meta-stargazer/recipes-core/systemd-conf/files/en.network <<EOF
[Match]
Name=en*
KernelCommandLine=!nfsroot

[Network]
DHCP=v4

[DHCPv4]
UseHostname=false
EOF

wlan.network

cat >../sources/meta-stargazer/recipes-core/systemd-conf/files/wlan.network <<EOF
[Match]
Name=en*
KernelCommandLine=!nfsroot

[Network]
DHCP=v4

[DHCPv4]
UseHostname=false
EOF

Step 5

Test the wired ethernet configuration with DHCP.

Rerun your build, provision the image onto an SDCard and verify that the eth0 interface is properly established:

raspberrypi3 login: root
Last login: Fri Oct  4 21:40:20 +0000 2019 on /dev/ttyS0.
root@raspberrypi3:~# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr B8:27:EB:3B:B5:02  
          inet addr:192.168.7.213  Bcast:192.168.7.255  Mask:255.255.255.0
          inet6 addr: fe80::ba27:ebff:fe3b:b502/64 Scope:Link
          inet6 addr: fdf6:e934:7387:1:ba27:ebff:fe3b:b502/64 Scope:Global
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:105 errors:0 dropped:4 overruns:0 frame:0
          TX packets:51 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:11855 (11.5 KiB)  TX bytes:7836 (7.6 KiB)

Step 6

Reconfigure your wired ethernet for static IP address assignment. Modify your eth.network file, adjusted for your network configuration, to look similar to the following:

[Match]
Name=eth*
KernelCommandLine=!nfsroot

[Network]
DNS=8.8.8.8
Address=192.168.7.200/24
Gateway=192.168.7.1

Note that similar setting will work in your wlan.network or en.network files if needed.

Rebuild, boot and verify:

Poky (Yocto Project Reference Distro) 2.7.1 raspberrypi3 ttyS0

raspberrypi3 login: root
root@raspberrypi3:~# ifconfig eth0
eth0      Link encap:Ethernet  HWaddr B8:27:EB:3B:B5:02  
          inet addr:192.168.7.200  Bcast:192.168.7.255  Mask:255.255.255.0
          inet6 addr: fdf6:e934:7387:1:ba27:ebff:fe3b:b502/64 Scope:Global
          inet6 addr: fe80::ba27:ebff:fe3b:b502/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:40 errors:0 dropped:1 overruns:0 frame:0
          TX packets:42 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:7756 (7.5 KiB)  TX bytes:6064 (5.9 KiB)

root@raspberrypi3:~# ping www.google.com
PING www.google.com (173.194.219.147): 56 data bytes
64 bytes from 173.194.219.147: seq=0 ttl=43 time=21.026 ms
64 bytes from 173.194.219.147: seq=1 ttl=43 time=26.633 ms
^C
--- www.google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 21.026/23.829/26.633 ms
root@raspberrypi3:~# 

Step 6

Finally, we will enable WiFi access on the Raspberry Pi. We need to add one more component to the system; the supplicant. This is the component that handles the encryption needs of the WiFi. For this demo we assume you are connecting to an encrypted SSID.

First, tell bitbake that we want to enable WiFi. Also, make sure the appropriate firmware binary is present in your build. Add the following to your conf/local.conf file:

DISTRO_FEATURES_append = " wifi "
IMAGE_INSTALL_append = " linux-firmware-rpidistro-bcm43430 "

Then, make sure the wpa-supplicant package is installed by adding the following to the previously created systemd_%.bbappend file:

RDEPENDS_${PN}_append = " wpa-supplicant "

Next, create a custom wpa_supplicant recipe append:

mkdir -p ../sources/meta-stargazer/recipes-connectivity/wpa-supplicant/files
cat >../sources/meta-stargazer/recipes-connectivity/wpa-supplicant/wpa-supplicant_%.bbappend <<EOF
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"

SRC_URI += "file://wpa_supplicant-nl80211-wlan0.conf"

SYSTEMD_AUTO_ENABLE = "enable"
SYSTEMD_SERVICE_${PN}_append = " wpa_supplicant-nl80211@wlan0.service  "

do_install_append () {
   install -d ${D}${sysconfdir}/wpa_supplicant/
   install -D -m 600 ${WORKDIR}/wpa_supplicant-nl80211-wlan0.conf ${D}${sysconfdir}/wpa_supplicant/

   install -d ${D}${sysconfdir}/systemd/system/multi-user.target.wants/
   ln -s ${systemd_unitdir}/system/wpa_supplicant@.service ${D}${sysconfdir}/systemd/system/multi-user.target.wants/wpa_supplicant-nl80211@wlan0.service
}
EOF

Create the configuration file by running the following command on your desktop. This will prompt you for the passphrase for your WiFi. You may want to then edit the file to remove the clear-text passphrase:

wpa_passphrase 'YOUR_SSID' >  ../sources/meta-stargazer/recipes-connectivity/wpa-supplicant/files/wpa_supplicant-nl80211-wlan0.conf

Now, you can again, rebuild, boot and verify:

root@raspberrypi3:~# ifconfig
eth0      Link encap:Ethernet  HWaddr B8:27:EB:3B:B5:02  
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

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:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

wlan0     Link encap:Ethernet  HWaddr B8:27:EB:6E:E0:57  
          inet addr:192.168.7.169  Bcast:192.168.7.255  Mask:255.255.255.0
          inet6 addr: fdf6:e934:7387:1:ba27:ebff:fe6e:e057/64 Scope:Global
          inet6 addr: fe80::ba27:ebff:fe6e:e057/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:25 errors:0 dropped:0 overruns:0 frame:0
          TX packets:46 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:4125 (4.0 KiB)  TX bytes:8439 (8.2 KiB)

root@raspberrypi3:~# ping www.google.com
PING www.google.com (74.125.138.147): 56 data bytes
64 bytes from 74.125.138.147: seq=0 ttl=43 time=24.171 ms
64 bytes from 74.125.138.147: seq=1 ttl=43 time=25.410 ms
^C
--- www.google.com ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 24.171/24.790/25.410 ms

Conclusion

In this tutorial, we discussed using systemd-networkd to manage the networking devices of your Yocto builds. Specifically, we enabled both wired and wireless interfaces, using both DHCP and Static IP addresses.

For further reading please visit

1 Like