Jump to content

Integration of Zchunk Delta Updates in SWUpdate within Yocto for NVIDIA Jetson Platforms

From RidgeRun Developer Wiki

Follow us on: YouTube Twitter LinkedIn Email Share this page

Share This Page


Integration of Zchunk Delta Updates in SWUpdate within Yocto for NVIDIA Jetson Platforms

This guide explains how to integrate zchunk-based delta updates into SWUpdate in a Yocto build for NVIDIA Jetson platforms, so a device can download only the changed chunks of an update artifact instead of downloading a full root filesystem image every time. This approach is useful when OTA bandwidth is expensive, update artifacts are large, and the target layout is designed to support safe updates. In a Jetson + Yocto workflow, the usual building blocks are Yocto, Extending meta-tegra for OTA Updates: The rr-nvidia-ota Layer, SWUpdate, zchunk, and a server that supports HTTP range requests.

What this guide covers

This page focuses on the practical integration path for teams building custom Jetson products with Yocto and looking for smaller OTA transfers. It covers the high-level architecture, the Yocto layers involved, the artifact flow, an example SWUpdate description, validation steps, and the most important operational caveats for production deployments.

Why use zchunk delta updates with SWUpdate?

A zchunk artifact is split into independently addressable chunks. This format compress can inspect the zchunk header, determine which chunks are already present locally, and download only the missing chunks from the server. SWUpdate documents this delta-update flow and explains that zchunk metadata can be used to identify which parts of an artifact must be fetched, while the target system reconstructs the final payload from the local base plus the downloaded chunks. This is especially relevant for embedded Linux systems with large root filesystem images and limited network budgets.

In practice, this means the update server still stores the full zchunk artifact, but the device may transfer far less data than the complete image when the old and new software versions are similar. The main benefit is reduced bandwidth usage. The main trade-off is more integration complexity and a stronger need for validation, rollback planning, and environment documentation.

Quick answer: when should you use this approach?

Use zchunk delta updates with SWUpdate on NVIDIA Jetson when all of the following are true:

  • Your Yocto image artifacts are large enough that full OTA downloads are costly.
  • Consecutive software releases share enough data that chunk reuse is meaningful.
  • Your artifact hosting endpoint supports HTTP range requests.
  • Your update design already addresses safety topics such as A/B partitions, rollback, signature verification, and power-loss handling.

If your product cannot tolerate recovery complexity, or if release-to-release changes are so large that chunk reuse is minimal, a full-image OTA workflow may be simpler and easier to validate. A simplified data flow is shown below:

Yocto build host
    |
    | 1. Build rootfs / image artifact
    v
New image artifact (for example, a rootfs tarball or filesystem image)
    |
    | 2. Convert artifact to .zck and extract header metadata as needed
    v
zchunk artifact + header metadata
    |
    | 3. Package header / metadata into the SWU bundle
    v
SWUpdate .swu package
    |
    | 4. Publish full zchunk artifact on HTTP server with Range support
    v
Artifact server
    |
    | 5. Target inspects zchunk metadata, reuses local chunks, downloads missing chunks
    v
Jetson target reconstructs payload and applies the update

Components and references

The integration usually involves the following components:

  • Yocto build environment for the Jetson product.
  • Extending meta-tegra for OTA Updates: The rr-nvidia-ota Layer or another OTA-oriented integration layer when applicable.
  • The official meta-swupdate layer for building SWUpdate within Yocto.
  • zchunk tooling for chunked artifact generation.
  • A target update strategy compatible with your platform layout and rollback plan.

Primary references:

Tested environment

Tested environment
Item Value
Jetson module NVIDIA Jetson AGX Orin Industrial and Jetson Orin NX
JetPack / L4T base L4T r36.4.4
Yocto release scarthgap (Yocto 5.0)
meta-tegra branch / commit scarthgap / 447c21467f65be2389f68a189b6871f13729d222
meta-swupdate branch / commit scarthgap / 81f4faa406e70dfa514e2f7642f97df33d3b84ae
SWUpdate version swupdate_git.bb, PV = "2025.12+git${SRCPV}", SRCREV = "a3da115bb972d8a07bc360f62c6df53d2a894c7a"
zchunk version 1.4.0
Host OS Ubuntu 24.04

Yocto integration prerequisites

At minimum, document the layers and packages required for the build. The exact names and configuration flags can vary by release, so the page should show the verified values used in the tested environment.

Required layers

In most Yocto-based integrations, the following layers are relevant:

  • openembedded-core and your base BSP layers
  • meta-openembedded, because meta-swupdate depends on it
  • meta-swupdate for SWUpdate recipes and SWU generation
  • meta-tegra for Jetson platform support

Example bblayers.conf excerpt

BBLAYERS += " \
  ${TOPDIR}/../layers/meta \
  ${TOPDIR}/../layers/meta-tegra \
  ${TOPDIR}/../layers/meta-oe \
  ${TOPDIR}/../layers/meta-python \
  ${TOPDIR}/../layers/meta-networking \
  ${TOPDIR}/../layers/meta-filesystems \
  ${TOPDIR}/../layers/meta-virtualization \
  ${TOPDIR}/../layers/meta-tegra-community \
  ${TOPDIR}/../layers/meta-tegra-support \
  ${TOPDIR}/../layers/meta-demo-ci \
  ${TOPDIR}/../layers/meta-tegrademo \
  ${TOPDIR}/../layers/meta-swupdate \
"

Requirements

Integration of SWUpdate

To add the delta update support using Zchunk, ensure that SWUpdate is integrated into the Yocto build, the following wiki provides instructions for integration:

Once SWUpdate is integrated into the build, it is important to verify that the machine layer configuration has the highest priority. This ensures that the changes required for delta update support are applied correctly.

In the following file, verify that:

<path-to-the-repository>/layers/<meta-custom-or-meta-tegra-demo-distro>/conf/layer.conf

Verify that the layer priority is set as follows:

BBFILE_COLLECTIONS += "tegrademo"
BBFILE_PATTERN_tegrademo = "^${LAYERDIR}/"
BBFILE_PRIORITY_tegrademo = "99"

Nginx

To test delta updates, it is necessary to host the .zck image file on a server. This allows verification of the correct behavior of SWUpdate when using this feature. For testing purposes, a local server can be set up on the PC.

To do this, install nginx:

sudo apt install nginx

Delta Update Support with Zchunk in SWUpdate

The tegra demo distro, as well as any meta-custom layer derived from this repository, already includes support for meta-swupdate and the required base configuration for delta updates. However, additional configuration is needed to enable the complete workflow for Zchunk-based delta updates.

Zchunk Requirements

Zchunk requires two files to generate and apply delta updates:

  • A .zck file (compressed data with chunking)
  • A .zckheader file, which contains metadata describing the changes between versions

The .zckheader file is used by SWUpdate to determine the differences and apply the delta update efficiently.

Generating Zchunk Artifacts for Delta Updates

To generate the required files, update the image recipe of the image you want to build. For example:

  • Tegra demo distro:
<path-to-the-repository>/layers/meta-tegrademo/recipes-demo/images/demo-image-base.bb
  • Custom layer:
<path-to-the-repository>/layers/meta-custom/recipes-custom/images/custom-image-base.bb

Add the following lines to the image recipe:

# Generate an ext4 rootfs plus the zchunk artifacts used by SWUpdate delta updates.
IMAGE_CLASSES += "image_types_zchunk"
IMAGE_FSTYPES += " ext4 ext4.zck ext4.zck.zckheader"

To enable delta updates, it is also necessary to configure the image recipe to use the correct output format for the artifact included inside the SWUpdate (.swu) bundle. This file format is essential for enabling the delta update mechanism.

Modify the following file:

<path-to-the-repository>/layers/<meta-custom-or-meta-tegra-demo-distro>/dynamic-layers/meta-swupdate/recipes-demo/images/swupdate-image-tegra.bb

Replace:

ROOTFS_FILENAME ?= "${SWUPDATE_CORE_IMAGE_NAME}-${MACHINE}.rootfs.tar.gz"

With:

# The .swu bundles the zchunk header artifact; the target uses it to compare
# against ROOTFS_DELTA_URL and download only the missing chunks from the .zck.
ROOTFS_FILENAME ?= "${SWUPDATE_CORE_IMAGE_NAME}-${MACHINE}.rootfs.ext4.zck.zckheader"

By default, the root filesystem is generated as a .tar.gz archive. However, this format is not suitable for Zchunk-based delta updates because it is a compressed archive that does not preserve a stable binary structure, making it impossible to perform efficient chunk-level comparisons between versions.

For delta updates, the output must use a format such as .ext4.zck, which supports chunking and allows SWUpdate to identify and transfer only the modified portions of the filesystem.

Configuring the URL for the Compressed RootFS Image

To reduce the size of the SWUpdate (.swu) bundle, the compressed root filesystem image is hosted on a server instead of being included directly in the bundle. This approach allows the .swu package to remain small by including only the .zck.header file, while the full compressed image is downloaded from the server during the update process. In the same file swupdate-image-tegra.bb:

# ROOTFS_DELTA_BASE_URL to the host reachable by the target, e.g.
ROOTFS_DELTA_BASE_URL = "http://<ip-of-the-pc>:8000"
ROOTFS_DELTA_URL ?= "${ROOTFS_DELTA_BASE_URL}/${SWUPDATE_CORE_IMAGE_NAME}-${MACHINE}.rootfs.ext4.zck"

In this setup, the image is hosted on a PC configured as a server (e.g., using nginx). Therefore, ROOTFS_DELTA_BASE_URL must be set to the IP address of that PC.

Ensure that both the target device and the host PC are connected to the same network (typically via Ethernet) so they share the same IP subnet. For example:

  • PC: 192.168.100.45
  • Target device: 192.168.100.47

And the server is properly configured and accessible on the specified port.

Add the Configuration for Delta Updates

To enable delta update support, you need to add the required SWUpdate configuration options for Zchunk and delta updates.

First, create a file named delta.cfg in the following path:

<path-to-the-repository>/layers/<meta-custom-or-meta-tegra-demo-distro>/dynamic-layers/meta-swupdate/recipes-support/swupdate/swupdate/delta.cfg

Add the following configuration options to the file:

CONFIG_DELTA=y
CONFIG_ZSTD=y

These options enable delta update support and the required compression backend.

Next, add the delta.cfg file to the SRC_URI in the swupdate_%.bbappend file located at:

<path-to-the-repository>/layers/<meta-custom-or-meta-tegra-demo-distro>/dynamic-layers/meta-swupdate/recipes-support/swupdate/swupdate_%.bbappend

Update SRC_URI as follows:

SRC_URI += "\
    file://systemd.cfg \
    file://hash.cfg \
    file://part-format.cfg \
    file://archive.cfg \
    file://disable-uboot.cfg \
    file://delta.cfg \
"

By adding delta.cfg to SRC_URI, the file is included during the SWUpdate build process. This ensures that delta update support is enabled when SWUpdate is compiled.

Modifications in sw-description for Delta Updates

To enable delta update support, the sw-description file must be modified to use the delta update mechanism instead of the default full image installation.

File to modify:

<path-to-the-repository>/layers/<meta-custom-or-meta-tegra-demo-distro>/dynamic-layers/meta-swupdate/recipes-demo/images/swupdate-image-tegra/sw-description
Key Changes

1. Change the image type to delta

Replace:

type = "archive";

With:

type = "delta";

This tells SWUpdate to perform a delta update instead of installing a full root filesystem.

2. Remove partition formatting

In the original configuration, partitions are formatted before installing the image:

partitions: (
    {
        type = "diskformat";
        device = "...";
        properties: {
            fstype = "ext4";
            force = "true";
        }
    }
);

Remove this section for delta updates. Delta updates require the existing filesystem as a base for comparison, so formatting the partition would break the update process.

3. Replace archive-based installation with delta properties

Replace the archive configuration:

type = "archive";
filesystem = "ext4";
path = "/";
installed-directly = true;
preserve-attributes = true;
sha256 = "...";

With:

type = "delta";
properties: {
    url = "@@ROOTFS_DELTA_URL@@";
    chain = "raw";
    source = "<active-partition>";
    source-size = "detect";
}

4. Configure delta-specific properties

Each delta image must include the following properties:

  • url: Points to the .zck file hosted on the server
  • chain: Defines how the update is applied (typically "raw")
  • source: The currently active partition used as the base for delta computation
  • source-size: Automatically detects the size of the source partition
Final sw-description for Delta Updates

After applying the required modifications, the complete sw-description file should look as follows:

software =
{
	version = "@@DISTRO_VERSION@@";

	@@MACHINE@@ = {
		hardware-compatibility: [ "1.0" ]
		system = {
			slot_a : {
				images: (
					{
						filename = "@@ROOTFS_FILENAME@@";
						type = "delta";
						device = "@@ROOTFS_DEVICE_PATH@@/APP_b";
						properties: {
							url = "@@ROOTFS_DELTA_URL@@";
							chain = "raw";
							source = "@@ROOTFS_DEVICE_PATH@@/APP";
							source-size = "detect";
						}
					},
					{
						filename = "@@DEPLOY_KERNEL_IMAGE@@";
						device = "@@ROOTFS_DEVICE_PATH@@/@@KERNEL_B_PARTNAME@@";
					},
					{
						filename = "@@DTBFILE@@";
						device = "@@ROOTFS_DEVICE_PATH@@/@@KERNEL_B_DTB_PARTNAME@@";
					}

				);
				files: (
					{
						filename = "tegra-bl.cap";
						path = "@@TEGRA_SWUPDATE_CAPSULE_INSTALL_PATH@@";
						properties = {create-destination = "true";}
						name = "tegra-bootloader-capsule"
						version = "@@TEGRA_SWUPDATE_BOOTLOADER_VERSION@@"
						install-if-different = @@TEGRA_SWUPDATE_BOOTLOADER_INSTALL_ONLY_IF_DIFFERENT@@
					},
					{
						filename = "@@ESP_ARCHIVE@@"
						type = "archive"
						installed-directly = true
						path = "/boot/efi"
						name = "tegra-bootloader-capsule"
						version = "@@TEGRA_SWUPDATE_BOOTLOADER_VERSION@@"
						install-if-different = @@TEGRA_SWUPDATE_BOOTLOADER_INSTALL_ONLY_IF_DIFFERENT@@
					}
				);
				scripts: (
					{
						filename = "tegra-swupdate-script.lua";
						type = "lua"
						sha256 = "$swupdate_get_sha256(tegra-swupdate-script.lua)";
					}
				);

			};
			slot_b : {
				images: (
					{
						filename = "@@ROOTFS_FILENAME@@";
						type = "delta";
						device = "@@ROOTFS_DEVICE_PATH@@/APP";
						properties: {
							url = "@@ROOTFS_DELTA_URL@@";
							chain = "raw";
							source = "@@ROOTFS_DEVICE_PATH@@/APP_b";
							source-size = "detect";
						}
					},
					{
						filename = "@@DEPLOY_KERNEL_IMAGE@@";
						device = "@@ROOTFS_DEVICE_PATH@@/@@KERNEL_A_PARTNAME@@";
					},
					{
						filename = "@@DTBFILE@@";
						device = "@@ROOTFS_DEVICE_PATH@@/@@KERNEL_A_DTB_PARTNAME@@";
					}
				);
				files: (
					{
						filename = "tegra-bl.cap";
						path = "@@TEGRA_SWUPDATE_CAPSULE_INSTALL_PATH@@";
						properties = {create-destination = "true";}
						name = "tegra-bootloader-capsule"
						version = "@@TEGRA_SWUPDATE_BOOTLOADER_VERSION@@"
						install-if-different = @@TEGRA_SWUPDATE_BOOTLOADER_INSTALL_ONLY_IF_DIFFERENT@@
					},
					{
						filename = "@@ESP_ARCHIVE@@"
						type = "archive"
						installed-directly = true
						path = "/boot/efi"
						name = "tegra-bootloader-capsule"
						version = "@@TEGRA_SWUPDATE_BOOTLOADER_VERSION@@"
						install-if-different = @@TEGRA_SWUPDATE_BOOTLOADER_INSTALL_ONLY_IF_DIFFERENT@@
					}
				);
				scripts: (
					{
						filename = "tegra-swupdate-script.lua";
						type = "lua"
						sha256 = "$swupdate_get_sha256(tegra-swupdate-script.lua)";
					}
				);
			};
		};
	}
}

Zchunk Chunk Size Tuning

By default, Zchunk generates relatively small chunks when creating .zck files. While this improves granularity for delta updates, it can also increase the time required to verify the root filesystem, since more chunks need to be processed.

To optimize this behavior, you can increase the chunk size. Larger chunks reduce the number of metadata entries and improve verification performance, at the cost of slightly less granularity in delta updates.

Why Use a Custom .bbclass

In Yocto, a .bbclass is used to encapsulate reusable build logic and configuration. Creating a custom class allows you to:

  • Centralize Zchunk tuning parameters.
  • Reuse the configuration across multiple images.
  • Avoid modifying upstream classes (keeping your layer maintainable and clean).

Creating the Zchunk Tuning Class

Create the bbclass for Zchunk

Navigate to your layer:

cd <path-to-the-repository>/layers/<meta-custom-or-meta-tegra-demo-distro>/
mkdir classes-recipe

Create a file named:

classes-recipe/zchunk-tuning.bbclass

Add the following content:

# Override the default zchunk conversion to use larger chunk sizes for rootfs
# images, reducing metadata overhead and improving delta-update efficiency.
ZCK_CHUNK_MIN_SIZE ?= "16384"
ZCK_CHUNK_MAX_SIZE ?= "129024"

CONVERSION_CMD:zck = "zck --output ${IMAGE_NAME}.${type}.zck -u --chunk-hash-type sha256 --chunk-min ${ZCK_CHUNK_MIN_SIZE} --chunk-max ${ZCK_CHUNK_MAX_SIZE} ${IMAGE_NAME}.${type}"

Applying the Class to the Image

To enable this tuning, add the custom class to IMAGE_CLASSES in your image recipe.

  • Tegra demo distro:
<path-to-the-repository>/layers/meta-tegrademo/recipes-demo/images/demo-image-base.bb
  • Custom layer:
<path-to-the-repository>/layers/meta-custom/recipes-custom/images/custom-image-base.bb

Modify:

IMAGE_CLASSES += "image_types_zchunk zchunk-tuning"

Extending Zchunk to Support Custom Chunk Sizes

Once the custom .bbclass is added, it is necessary to extend Zchunk itself to support configurable chunk sizes. By default, Zchunk does not expose CLI options to control minimum and maximum chunk sizes, so a patch must be applied. Navigate to your layer and create the required directory:

cd <path-to-the-repository>/layers/<meta-custom-or-meta-tegra-demo-distro>/
mkdir -p recipes-support/zchunk/

Create the following file:

recipes-support/zchunk/zchunk_%.bbappend

Add the following content:

SUMMARY = "zchunk CLI chunk-size tuning patch"
DESCRIPTION = "Applies a patch to zchunk that exposes minimum and \
maximum chunk size CLI options so Yocto image conversions can tune zchunk \
chunking behavior."

FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"

SRC_URI += " file://0001-zck-add-chunk-min-max-cli-options.patch"

Create a directory to store the patch:

cd <path-to-the-repository>/layers/<meta-custom-or-meta-tegra-demo-distro>/recipes-support/zchunk/
mkdir zchunk

Create the patch file:

Note: This patch modifies upstream Zchunk behavior by exposing additional CLI options. As a result, it may need to be reviewed and maintained across Zchunk version updates to ensure compatibility.

0001-zck-add-chunk-min-max-cli-options.patch

Add the patch content

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: CarlosQG <carlos.quiros@ridgerun.com>
Date: Tue, 31 Mar 2026 09:00:00 -0600
Subject: [PATCH] zck: add chunk min/max CLI options

Expose chunk size bounds already supported by the zchunk library so
Yocto image conversions can tune chunking without patching upstream
classes or custom wrappers.
---
 src/zck.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/src/zck.c b/src/zck.c
--- a/src/zck.c
+++ b/src/zck.c
@@ -31,6 +31,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdint.h>
+#include <errno.h>
+#include <limits.h>
 #include <stdbool.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -57,6 +59,10 @@
      "Set zstd compression dictionary to FILE"},
     {"manual-chunk",       'm', 0,           0,
      "Don't do any automatic chunking (implies -s)"},
+    {"chunk-min",          201, "SIZE",      0,
+     "Set minimum chunk size in bytes"},
+    {"chunk-max",          202, "SIZE",      0,
+     "Set maximum chunk size in bytes"},
     {"chunk-hash-type",     'h', "HASH",     0,
      "Set hash type to one of sha256, sha512, sha512_128"},
     {"uncompressed",       'u', 0,           0,
@@ -74,6 +80,8 @@
   zck_log_type log_level;
   char *split_string;
   bool manual_chunk;
+  long long chunk_min_size;
+  long long chunk_max_size;
   char *output;
   char *dict;
   char *compression_format;
@@ -82,6 +90,25 @@
   zck_hash chunk_hashtype;
 };
 
+static error_t parse_chunk_size(long long *value, const char *arg, const char *name) {
+    char *endptr = NULL;
+    unsigned long long parsed = 0;
+
+    errno = 0;
+    parsed = strtoull(arg, &endptr, 10);
+    if(errno != 0 || endptr == arg || *endptr != '\0') {
+        LOG_ERROR("Invalid %s value: %s\n", name, arg);
+        return EINVAL;
+    }
+    if(parsed == 0 || parsed > INT_MAX) {
+        LOG_ERROR("%s value must be between 1 and %d bytes\n", name, INT_MAX);
+        return EINVAL;
+    }
+
+    *value = (long long) parsed;
+    return 0;
+}
+
 static error_t parse_opt (int key, char *arg, struct argp_state *state) {
     struct arguments *arguments = state->input;
 
@@ -104,6 +131,14 @@
         case 'm':
             arguments->manual_chunk = true;
             break;
+        case 201:
+            if(parse_chunk_size(&arguments->chunk_min_size, arg, "minimum chunk size") != 0)
+                return EINVAL;
+            break;
+        case 202:
+            if(parse_chunk_size(&arguments->chunk_max_size, arg, "maximum chunk size") != 0)
+                return EINVAL;
+            break;
         case 'h':
             if (!strcmp(arg, "sha256"))
                 arguments->chunk_hashtype = ZCK_HASH_SHA256;
@@ -277,6 +312,18 @@
             LOG_ERROR("%s\n", zck_get_error(zck));
             exit(1);
         }
+    }
+    if(arguments.chunk_max_size > 0) {
+        if(!zck_set_ioption(zck, ZCK_CHUNK_MAX, arguments.chunk_max_size)) {
+            LOG_ERROR("%s\n", zck_get_error(zck));
+            exit(1);
+        }
+    }
+    if(arguments.chunk_min_size > 0) {
+        if(!zck_set_ioption(zck, ZCK_CHUNK_MIN, arguments.chunk_min_size)) {
+            LOG_ERROR("%s\n", zck_get_error(zck));
+            exit(1);
+        }
     }
     if(arguments.uncompressed) {
         if(!zck_set_ioption(zck, ZCK_UNCOMP_HEADER, 1)) {

-- 
2.43.0

This step ensures that Zchunk supports the following new CLI options:

  • --chunk-min: Defines the minimum chunk size
  • --chunk-max: Defines the maximum chunk size

By default, these parameters are not exposed, which prevents fine-tuning of chunk behavior during image generation.

Overriding Chunk Size Parameters in local.conf

If you want to use other values in this parameter it can set in the local.conf which it in the next path:

<path-to-the-repository>/build/conf/local.conf

Add the following content:

# Bound zchunk's automatic chunking to reduce metadata and source-side hashing work.
ZCK_CHUNK_MIN_SIZE = "32768"
ZCK_CHUNK_MAX_SIZE = "262144"

Build the image with SWUpdate

To ensure to generate the swupdate bundle with the changes of the delta update and the image with the compress format it clean the demo-image-base and the swupdate:

  • Tegra demo distro:
bitbake -c clean demo-image-base swupdate-image-tegra
  • Custom layer:
bitbake -c clean custom-image-base swupdate-image-tegra

To generate an image that includes SWUpdate support, run:

bitbake swupdate-image-tegra

Host the PC as a server.

To test delta updates, the PC must be configured as a server to host the .zck image so the target board can download the required chunks during the update process.

1. Create a directory to host the image

sudo mkdir -p /tmp/zchunk

2. Copy the generated .zck file from the build.

sudo cp -av <path-to-the-repository>/build/tmp/deploy/images/<machine>/<image>-<machine>.rootfs-<timestamp>.ext4.zck /tmp/zchunk/

3. Create a symbolic link with the expected name

SWUpdate expects the file to have a specific name (without the timestamp), so create a symbolic link:

cd /tmp/zchunk/
sudo ln -sf <image>-<machine>.rootfs-<timestamp>.ext4.zck <image>-<machine>.rootfs.ext4.zck

4. Set the correct permissions

sudo chmod 755 /tmp/zchunk
sudo chmod 644 /tmp/zchunk/*.zck

This ensures the server can properly access and serve the files without permission issues.

5. Create the nginx configuration file

nano /tmp/swupdate.conf

Add the following content:

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    sendfile on;
    tcp_nopush on;

    server {
        listen 8000;
        server_name _;

        root /tmp/zchunk;

        location / {
            autoindex on;
            default_type application/octet-stream;
            add_header Accept-Ranges bytes;
        }
    }
}

6. Run nginx with the custom configuration

sudo nginx -c /tmp/swupdate.conf

The server hosts the .zck file and serves it over HTTP on port 8000. The Accept-Ranges header is required to enable partial downloads, which are used by zchunk to retrieve only the necessary chunks during delta updates. It is also important to ensure that the PC firewall allows incoming connections on port 8000, so the target board can successfully access and download the required data.

Flash the Image

Once the build process is complete and the local server is configured, you can proceed to flash the generated image onto the target board. For JetPack 6, it is recommended to follow the JetPack 6 Integration – Flashing Jetson Platform wiki page.

This step programs the board with the image that includes SWUpdate support. Once the flashing process is complete, verify that SWUpdate is correctly included and available on the deployed image:

root@tegra-demo-distro:~# which swupdate
/usr/bin/swupdate

Deploy and test

Once the image has been verified on the board, return to the build environment. In the deploy directory for the target machine, you will find the generated .swu file at:

cd <path-to-build-directory>/build/tmp/deploy/images/<machine>

The .swu file is named according to the target machine, following this format:

swupdate-image-tegra-<machine>.rootfs-<timestamp>.swu

Transfer the generated .swu file to the target board using scp. For example:

 scp swupdate-image-tegra-<machine>.rootfs-<timestamp>.swu <user>@<ip-of-the-board>:/tmp/

Once is complete transfer to the board, run the update with:

cd /tmp/
swupdate -i /tmp/swupdate-image-tegra-<machine>.rootfs-<timestamp>.swu

After running the update file, reboot the board to apply the update. After the reboot process, verify the following:

  • The root partition should change
  • The nvbootctrl dump-slots-info output should show boot from the alternate boot slot with Capsule update status:1.
root@tegra-demo-distro:~# nvbootctrl dump-slots-info
Current version: 36.4.4
Capsule update status: 1
Current bootloader slot: B
Active bootloader slot: B
num_slots: 2
slot: 0,             status: normal
slot: 1,             status: normal

Troubleshooting

The target downloads the full artifact instead of only changed chunks

Common causes include:

  • releases are too different for meaningful chunk reuse
  • chunking parameters changed between versions
  • the wrong base artifact is present on the device
  • the target cannot reuse local data as expected
  • the artifact host does not support range requests correctly

SWUpdate cannot apply the delta package

Common causes include:

  • handler configuration mismatch
  • incorrect properties in sw-description
  • wrong target partition path
  • missing dependencies in the Yocto image
  • mismatch between the SWUpdate version and the packaging method

Range requests work in curl but not in the device workflow

Check for:

  • proxy or CDN behavior
  • authentication redirects
  • headers stripped by a reverse proxy
  • device-side certificate or TLS problems

Summary

zchunk delta updates in SWUpdate can reduce OTA transfer size for Yocto-based NVIDIA Jetson products when the system has a good base artifact for chunk reuse, the server supports range requests, and the update layout is validated for safety. The strongest version of this page is not just a generic procedure: it clearly documents the exact Yocto layers, software versions, target layout, SWUpdate description, hosted artifact flow, measured bandwidth savings, and Jetson validation results.

FAQ

What problem does zchunk solve in SWUpdate?
zchunk helps reduce OTA download size by allowing the target to reuse unchanged chunks from an existing artifact and fetch only the missing chunks required to reconstruct the new payload.
Do I need a special server to host the update artifact?
You do not necessarily need a proprietary OTA server, but the hosting endpoint should reliably support HTTP range requests so the device can fetch only the byte ranges it needs from the zchunk artifact.
Is this approach always better than full-image OTA updates?
No. It is most useful when consecutive releases are similar enough for chunk reuse to be significant. Full-image updates can still be easier to validate and support in some products.
What should be benchmarked on Jetson?
At minimum, benchmark transferred bytes, update time, CPU load during reconstruction, storage overhead, and rollback behavior under controlled network conditions.
What should be documented for reproducibility?
Document the Jetson module, carrier board, JetPack or L4T release, Yocto release, meta-tegra and meta-swupdate branches, SWUpdate version, zchunk version, and host OS used for the build and validation.

Related pages

Contact Us

Need help integrating OTA updates into a Jetson Yocto product, validating an A/B update design, or measuring the real bandwidth savings of a delta-update workflow? Contact RidgeRun through the official support and inquiry channel:

References



For direct inquiries, please refer to the contact information available on our Contact page. Alternatively, you may complete and submit the form provided at the same link. We will respond to your request at our earliest opportunity.


Links to RidgeRun Resources and RidgeRun Artificial Intelligence Solutions can be found in the footer below.


Cookies help us deliver our services. By using our services, you agree to our use of cookies.