In the previous article we discussed the fundamentals and implementation of Embedded Linux update systems. Here we discuss a selection of off-the-shelf open-source update systems that are available to integrate with your Embedded Linux project today.
This update system feels very professional and usable out of the box. It uses a dual-rootfs update system very similar to that which was described in the previous article. It integrates tightly with U-Boot to allow fallback in the case of a non-booting image.
It’s quite easy to get started with Mender, as there is good clear step-by-step documentation on how to set up and integrate the various components. They provide reference implementations on popular platforms like the Raspberry Pi and BeagleBone Black, these can give you an idea on the amount of work required to get it working on your platform.
I found it took about three days to integrate and get working. There were many small changes to get it working with my Yocto build setup (based on Morty). It requires some OpenEmbedded expertise to work around these issues. U-Boot expertise is needed to integrate the dual-booting mechanism correctly.
At the end of this it outputs an “sdimg”, containing the bootloader and filesystem, which needs to be somehow written into your flash memory. How you do this depends on your target hardware. It also outputs what are called ‘artifacts’ which contains the new filesystem image and various metadata.
The artifacts can be installed via the Mender command line tool for a manual install (which can then theoretically be extended to automatic install off a USB stick). Artifacts can also be uploaded onto the backend update web-service via a web interface and from here it can be pushed down to individual units.
The web-interface which controls the backend update server is well-designed and easy to use. Setting it up is done via Docker, which makes initial set-up very straightforward. Expertise in Docker will be required in a full production-ready system. From this web interface you can see all currently deployed devices in the field, and push updates to them individually or in groups.
click for larger image
Figure 1: Mender contains a bespoke web interface for pushing updates to devices (Source: Mender)
The majority of Mender is written in the Go programming language. Some expertise in Go will be necessary for long-term adoption and production releases. While this is still an uncommon language in the embedded world, it may become more widely used in the future.
You are tied to a single hard-coded boot device (e.g: /dev/mmcblk0), so there is no straightforward way to allow booting from multiple mediums. It also makes a lot of assumptions about your system such as various options in the bootloader and the kernel (e.g: including support for certain filesystems). Crucially, it requires systemd which may render it unsuitable for some projects.
This update system is highly configurable. You configure it using the “kconfig” system which will be familiar to most Embedded Linux developers. For a few examples of configuration options: it supports several bootloaders (U-Boot, GRUB, EFI Boot Guard); it can sign and verify signed images based on a given public key; it can support encryption of images using symmetric key encryption.
Figure 2: the configuration system for SWUpdate (Source: SWUpdate)
Each update consists of a CPIO archive containing metadata in the form of a ‘sw-description’ file and the actual data files needed to perform the update. This will generally contain a list of filesystems and into which block devices they should be placed. The update file must be created manually by the user; it does not fall out of the build system.
Unlike Mender, SWUpdate does not step in and handle the details of how your system needs to be set up. Mender will go some way to patching your u-boot environment for you, SWUpdate will need you to work out the low-level implementation details for the “ping-pong” A-B dual rootfs setup yourself.
SWUpdate can provide command line installation. It also provides a back-end update system similar to Mender’s which is based on Eclipse hawkBit, which runs in conjunction with a daemon running on the target called ‘Suricatta’ which handles the calls to SWUpdate. It can also run an embedded http server on the device itself from which updates can be uploaded and installed.
It provides by default a stripped down image recipe designed to run as an initramfs recovery image. It seems that, from my experience so far, the system is designed for a recovery partition update over a dual rootfs update (the pros and cons of these were discussed in the previous article). It seems to be impossible or at least very difficult to integrate dual rootfs updates with the background OTA update daemon ‘Suricatta’.
The majority of SWUpdate is written in C, so most Embedded Linux developers can easily make modifications or perform debug. The developers also have incorporated the idea of ‘handlers’ into the application to allow easy extensions by other coders. These can implement extra update functionality, such as firmware download to other silicon on the board.
Like Mender, SWUpdate makes some requirements on the user but these are limited and some are even optional due to the configurable nature of the system.
RAUC is designed to be a more lightweight update system than the previous two update systems, the main binary being only approx. 512K compared to 1.3M for SWUpdate and 6.9M for Mender (these are rough calculations based on output from Yocto, does not take into account dependencies, different build targets, etc.).
It outputs what it calls “bundles” from the build system. These bundles contain compressed filesystems and metadata. They are required always to be digitally signed which is a core design concept of RAUC. It programs filesystem images into various “slots” which can then be marked working or broken or ready for update. It will interface with the bootloader environment to decide whether
RAUC requires certain options in the kernel (e.g: SQUASHFS support) and also has some software dependencies in the root filesystem. RAUC, like SWUpdate, is written in C. It does not implement streaming where Mender does and SWUpdate can do.
Like SWUpdate, it supports using Eclipse hawkBit as a back-end update system, allowing you to push down updates to devices from a web interface.
click for larger image
Figure 3: Eclipse hawkBit can be used as the web interface to push updates down to devices, it can be integrated with RAUC and SWUpdate (Source: Eclipse hawkBit)
File-based update systems (as described in the previous article) have not been mentioned here. Others have been missed for brevity.
The decision of which system to use really depends on the project. It seems that Mender is probably easier to get started with, whereas SWUpdate might be useful for integrating with an update system that has already partially been developed in house, and RAUC might be used as an alternative to SWUpdate.
Ville Baillie is a software engineer at ByteSnap Design, an award winning software and hardware consultancy. He is a graduate of Physics at Warwick University and now specialises in developing device drivers for Embedded Linux applications.