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

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 - Create custom layer

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 - Modify systemd recipe in custom layer

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 - Modify systemd-conf recipe in custom layer

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=wlan*
KernelCommandLine=!nfsroot

[Network]
DHCP=v4

[DHCPv4]
UseHostname=false
EOF

Step 5 - Verify wired connectivity using 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 - Verify wired connectivity using static IP assignment

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 7 - Enable and test WiFi

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


If this tutorial was useful to you, please press like, or leave a thank you note to the contributor who put valuable time into this and made it available to you. It will be much appreciated!

1 Like

@drewmoseley nice!
Cosmetic suggestion: Instead of headers Step 1 - 7, perhaps use more descriptive headers to highlight what each section is about?

Awesome guide! I followed the first parts your guide with great success, and managed to get my raspberry configured with a fixed ip with no problems.

I did however run into issues when trying to go through with the wlan section. I think I discovered a type on wlan.network that specifies “Name=en*” (I tried “Name=wlan*” but that did not help). I keep getting the following error messages when booting up:

[    2.854532] systemd[1]: multi-user.target: Wants dependency dropin /etc/systemd/system/multi-user.target.wants/wpa_supplicant-nl80211@%i.service is not a valid unit name, ignoring.
[    2.871027] systemd[1]: multi-user.target: Wants dependency dropin /etc/systemd/system/multi-user.target.wants/wpa_supplicant-nl80211@wlan0.service target /lib/systemd/system/wpa_supplicant@.service has different name
[    2.890835] systemd[1]: multi-user.target: Wants dependency dropin /etc/systemd/system/multi-user.target.wants/wpa_supplicant-wired@%i.service is not a valid unit name, ignoring.
[    2.975344] systemd[1]: multi-user.target: Wants dependency dropin /etc/systemd/system/multi-user.target.wants/wpa_supplicant-nl80211@%i.service is not a valid unit name, ignoring.
[    2.991803] systemd[1]: multi-user.target: Wants dependency dropin /etc/systemd/system/multi-user.target.wants/wpa_supplicant-nl80211@wlan0.service target /lib/systemd/system/wpa_supplicant@.service has different name

This doesn’t tell me anything but I am hopeing it makes more sense to you…

@elchtzeasar welcome to Mender hub. I’m glad you found this useful. Well-spotted on the copy/paste error in wlan.network. I’ve fixed that in the post.

As for your other error, I’ve never seen that. It feels to me like something is mistyped somewhere in your recipe files. It seems to be complaining about the naming, thus my hunch. Although it’s not completely clear that is an error.

Do you see the wlan device when running “ifconfig -a”?

Drew

Thanks for a quick response. ifconfig -a did not list wlan0, but I found some other guides, and someone had listed dmesg for brcmfmac. I tried it and realized it was trying to load 43455 instead of 43430. I updated my local.conf and have now come alot further.

Before the update I had:
root@raspberrypi3:~# dmesg | grep brcmfmac
[ 4.588919] brcmfmac: F1 signature read @0x18000000=0x15264345
[ 4.597649] brcmfmac: brcmf_fw_map_chip_to_name: using brcm/brcmfmac43455-sdio.bin for chip 0x004345(17221) rev 0x000006
[ 4.610487] usbcore: registered new interface driver brcmfmac
[ 4.617209] brcmfmac mmc1:0001:1: Direct firmware load for brcm/brcmfmac43455-sdio.bin failed with error -2
[ 5.681293] brcmfmac: brcmf_sdio_htclk: HT Avail timeout (1000000): clkctl 0x50
[ 6.693172] brcmfmac: brcmf_sdio_htclk: HT Avail timeout (1000000): clkctl 0x50

I changed to "IMAGE_INSTALL_append = " linux-firmware-rpidistro-bcm43455 " in local.conf and I can now see a wlan0 when running “ifconfig -a”, but still get the same error messages from wpa_supplicant and wlan0 is not setup.

I can however run the following command which gets my wlan0 up and running:
/usr/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-nl80211-wlan0.conf -iwlan0 &

I will try to troubleshoot my last issues and post the solution here in case it helps anyone else…

I have now realized that my /etc/systemd/system/multi-user.target.wants/wpa_supplicant-nl80211@wlan0.service file contains the rule: ExecStart=/usr/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -i%I. Changing the recipe to create /etc/wpa_supplicant/wpa_supplicant-wlan0.conf instead of wpa_supplicant-nl80211-wlan0.conf makes things work from startup.