Skip to content

feat(extensions): add netboot extension for TFTP+NFS diskless boot#9656

Draft
iav wants to merge 3 commits intoarmbian:mainfrom
iav:enh/netboot-extension
Draft

feat(extensions): add netboot extension for TFTP+NFS diskless boot#9656
iav wants to merge 3 commits intoarmbian:mainfrom
iav:enh/netboot-extension

Conversation

@iav
Copy link
Copy Markdown
Contributor

@iav iav commented Apr 11, 2026

Summary

Adds an opt-in netboot extension that produces a full network-boot payload — kernel, DTB, optional uInitrd, pxelinux.cfg and an NFS-exportable rootfs — from a regular Armbian build. For netboot the only thing that has to live on the device's local storage is U-Boot itself: the kernel and DTB come from TFTP, / is mounted over NFS, nothing else on mmc/eMMC/USB is touched during early boot.

Today ROOTFS_TYPE=nfs alone only gives a hybrid image (kernel+DTB still on SD/eMMC, only / over NFS). This PR keeps that path working and layers a real netboot flow on top via a new ROOTFS_TYPE=nfs-root.

What changes

  • lib/functions/configuration/main-config.sh — new ROOTFS_TYPE=nfs-root case branch, symmetric with the existing fs-f2fs-support / fs-btrfs wiring: the branch auto-enables the netboot extension so ROOTFS_TYPE=nfs-root is the single switch that selects the full netboot flow. check_filesystem_compatibility_on_host is skipped for both nfs and nfs-root — the host-side check is a sanity net for block-device targets and falsely rejects valid NFS configurations.

  • extensions/netboot/netboot.sh — new, directory-based extension. Directory layout (rather than a single extensions/netboot.sh file) exists so the long-form usage guide can live next to the code as README.md; inlining documentation of that size into the script body would be unwieldy. Hooks:

    • extension_prepare_config — validate variables, compute defaults for NETBOOT_TFTP_PREFIX / NETBOOT_NFS_PATH (shared by LINUXFAMILY/BOARD/BRANCH/RELEASE, or per-host when NETBOOT_HOSTNAME is set), normalize NETBOOT_CLIENT_MAC to the 01-<mac> PXELINUX form, fail fast on bad ROOTFS_COMPRESSION/ROOTFS_EXPORT_DIR combinations before debootstrap.
    • custom_kernel_config — enable ROOT_NFS, NFS_FS, NFS_V3, IP_PNP, IP_PNP_DHCP so root=/dev/nfs ip=dhcp works without an initrd.
    • post_customize_image — drop armbian-resize-filesystem.service (meaningless on NFS root) and /root/.not_logged_in_yet (the armbian-firstlogin interactive wizard blocks bring-up when there is no interactive console). armbian-firstrun.service stays — it only regenerates SSH host keys.
    • host_pre_docker_launch — bind-mount ROOTFS_EXPORT_DIR into the build container when it lives outside ${SRC}, so the single-step builder-as-NFS-server workflow works the same inside and outside Docker.
    • pre_umount_final_image — assemble the TFTP tree (Image/zImage, dtb/, uInitrd), write pxelinux.cfg/{default.example | 01-<mac>} with the right FDT/FDTDIR line and an explicit INITRD directive when uInitrd is present (U-Boot's PXE parser only loads an initramfs when the stanza names it), expose a netboot_artifacts_ready hook for userpatches that deploy to a real server.
  • lib/functions/image/rootfs-to-image.sh — two new controls for NFS-rootfs builds (both ROOTFS_TYPE=nfs and nfs-root):

    • ROOTFS_COMPRESSION=gzip|zstd|none (default gzip). gzip.tar.gz, zstd.tar.zst, none → no archive at all. Rejected early if none is set without ROOTFS_EXPORT_DIR. The tar | pv | compressor pipeline now runs in a set -o pipefail subshell so a broken archive step actually fails the build instead of producing a silently truncated file.
    • ROOTFS_EXPORT_DIR=/abs/path — also (or only) rsync the rootfs tree into this directory. Can point anywhere on the build host's filesystem — inside or outside the Armbian tree (the extension bind-mounts external paths into the Docker container automatically). If the path is an NFS mount or any other network filesystem, the build writes directly to the remote server with no intermediate archive. The rsync uses --delete so a re-used export dir stays in sync with the new build instead of accumulating stale files from previous runs. Combined with ROOTFS_COMPRESSION=none this turns deploy-to-NFS-server into a single build step.
    • ROOTFS_ARCHIVE_PATH is exported so downstream hooks (the new netboot_artifacts_ready) can reference the produced archive.
  • lib/functions/image/partitioning.shprepare_partitions skips the root partition entry for nfs-root the same way it does for nfs, and the SD-size sanity check no longer applies to either (there is no image file to size).

  • config/templates/nfs-boot.cmd.template — previously sunxi/arm32-only (zImage + bootz). Made arch-agnostic so the hybrid ROOTFS_TYPE=nfs path builds for arm64 boards too.

  • extensions/netboot/README.md — long-form guide: variable reference, server setup (tftpd-hpa + nfs-kernel-server), DHCP 66/67 config (OpenWRT + others), per-host / per-MAC deployments, firstrun vs firstlogin, end-to-end helios64 example, troubleshooting.

Variables (quick reference)

All optional. ROOTFS_TYPE=nfs-root alone gives you a shared-rootfs build with a pxelinux.cfg/default.example file.

Variable Default Purpose
NETBOOT_SERVER (empty) TFTP/NFS server IP. Empty → nfsroot= keeps ${serverip} literal for U-Boot to fill from DHCP siaddr.
NETBOOT_TFTP_PREFIX armbian/${LINUXFAMILY}/${BOARD}/${BRANCH}-${RELEASE} Path prefix under TFTP root.
NETBOOT_NFS_PATH /srv/netboot/rootfs/shared/... or /srv/netboot/rootfs/hosts/<hostname> Absolute NFS path used in nfsroot=.
NETBOOT_HOSTNAME (empty) Per-host rootfs under hosts/<hostname>/ — each machine owns its own writable copy.
NETBOOT_CLIENT_MAC (empty) When set, PXE config is written as 01-<mac> (per-MAC PXELINUX override). Accepts : or -, normalized to lowercase.
ROOTFS_COMPRESSION gzip gzip / zstd / none.
ROOTFS_EXPORT_DIR (empty) When set, rsync the rootfs tree here in addition to (or instead of) the archive.

Test plan

Validated end-to-end on helios64 (rockchip64, edge/resolute, ttyS2 @ 1500000), Armbian 26.05:

  • Baseline build (ROOTFS_TYPE=nfs-root NETBOOT_SERVER=192.168.1.125, shared NFS path, FDTDIR fallback for boards without BOOT_FDT_FILE, no hardcoded console=). 6:57 min, all artifacts correct.
  • Per-host + per-MAC (NETBOOT_HOSTNAME=helios64-a NETBOOT_CLIENT_MAC=aa:bb:cc:dd:ee:ff). pxelinux.cfg/01-aa-bb-cc-dd-ee-ff contains nfsroot=.../hosts/helios64-a. 7:44 min.
  • ROOTFS_COMPRESSION=zstd — produces .tar.zst, ROOTFS_ARCHIVE_PATH set correctly. 460 MB vs 503 MB gzip.
  • ROOTFS_COMPRESSION=none ROOTFS_EXPORT_DIR=... — single-step tree workflow, 1.5 GB tree in export dir, no archive produced. 5:17 min.
  • ROOTFS_COMPRESSION=none without ROOTFS_EXPORT_DIR — fails fast in extension_prepare_config before debootstrap, not hours later.
  • End-to-end boot test: TFTP tree deployed to tftpd-hpa + NFS rootfs via rsync to nfs-kernel-server. DHCP options 66/67 on OpenWRT. Helios64 cold boot → U-Boot bootflow scan -lb → TFTP → booti → kernel → ip_auto_config → NFS mount → systemd graphical.target → login prompt on ttyS2@1500000. No armbian-firstlogin wizard, no resize2fs errors, armbian-firstrun.service regenerates SSH host keys normally. Verified twice: once with archive workflow + manual unpack, once with tree workflow + rsync deploy.
  • helios4 (mvebu, armhf, U-Boot v2025.10) — second SoC family. PXE netboot: DHCP → TFTP (zImage + DTB) → bootz → kernel → NFS root → systemd → login prompt. No initrd needed (see notes below).
  • Other boards / other SoC families — review welcome, especially from boards with BOOT_FDT_FILE set (the FDTDIR vs FDT code path is exercised by helios64's missing BOOT_FDT_FILE, but a board with it set should also work).

Known issues found during helios4 testing (not blockers for this PR):

  • RD image overlaps OS image on mvebu: ramdisk_addr_r (0x2880000) is only 8 MB above kernel_addr_r (0x2080000), but zImage 6.12 is 8.1 MB → U-Boot refuses to boot with initrd. Workaround: omit INITRD from PXE config — kernel with CONFIG_ROOT_NFS=y mounts NFS root directly without initrd.
  • DNS not working after NFS boot: kernel ip=dhcp writes DNS to /proc/net/pnp but systemd-resolved doesn't read it → "No DNS servers known". Workaround: resolvectl dns <iface> <gateway>. Needs a networkd .network file or oneshot service in post_customize_image (future improvement).

Post-review update: architecture reworked after CodeRabbit #1 — the extension no longer forces ROOTFS_TYPE from inside extension_prepare_config (too late in the config lifecycle); instead a new ROOTFS_TYPE=nfs-root case branch in main-config.sh enables the extension, symmetric with existing filesystem-support extensions. pipefail on the archive pipeline (#4), rsync --delete on the export dir (#5), and an explicit INITRD directive when uInitrd is present (#2) are all in.

Related work

A companion PR to armbian/documentation will add Developer-Guide_Netboot.md with the short overview + variable reference; this extension's README.md is the long-form guide and is linked from that page.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Network boot (NFS/TFTP) support with configurable rootfs compression and export options
    • ARM64 kernel selection with fallback to 32-bit boot
    • Automated PXE configuration and netboot artifact staging
  • Documentation

    • Comprehensive netboot setup guide covering server configuration, deployment workflows, and troubleshooting

iav and others added 2 commits April 12, 2026 00:12
…YPE=nfs

ROOTFS_TYPE=nfs produces a rootfs tarball via `tar cp ... | gzip` in
rootfs-to-image.sh and never mounts NFS on the build host. The NFS
client runs on the target's kernel at boot time, so host-side NFS
filesystem support is irrelevant. Additionally, the check runs inside
the Armbian docker launcher where /lib/modules is empty, causing
`modprobe nfs` to fail even when the host kernel has nfs.ko available.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous template was hardcoded for sunxi arm32 — `zImage`/`bootz`,
`console=tty1 console=ttyS0,115200`, `disp.screen0_output_mode=...`,
`ext4load/fatload mmc 0`. It did not work on arm64 boards (e.g.
rockchip64/helios64) and baked in a 115200 baud that breaks non-standard
UART speeds (helios64 runs at 1500000).

Rewrites the U-Boot hush script to:
- Prefer `Image` + `booti` (arm64), fall back to `zImage` + `bootz` (arm32).
- Load via `${devtype} ${devnum}:${distro_bootpart}` from U-Boot's distro
  bootflow scanner instead of hardcoded `mmc 0`.
- Drop the `console=` overrides — let the kernel resolve the console from
  DTB `/chosen/stdout-path`, keeping `earlycon` for early output.
- Drop sunxi-specific `disp.screen0_output_mode` and legacy `.next`/
  `script.bin` probe paths.

For the full TFTP+NFS netboot flow see the new `netboot` extension; this
template remains the hybrid path where the kernel + DTB live on a local
boot partition and only the rootfs is NFS-mounted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@iav iav requested review from a team, EvilOlaf, TRSx80, igorpecovnik and littlecxm as code owners April 11, 2026 23:32
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 11, 2026

📝 Walkthrough

Walkthrough

This PR introduces a comprehensive netboot extension for Armbian that enables network boot via TFTP and NFS root filesystems. Changes include a revised U-Boot boot script for NFS root support, a new netboot extension system with artifact staging, configurable rootfs compression/export, and extensive documentation covering deployment workflows and troubleshooting.

Changes

Cohort / File(s) Summary
U-Boot NFS Boot Configuration
config/templates/nfs-boot.cmd.template
Refactored kernel command-line construction, replaced hardcoded boot media loading with distro boot partition selection, added arm64 Image/booti support with fallback to zImage/bootz, and improved variable quoting robustness.
Netboot Extension Implementation
extensions/netboot/netboot.sh
New extension script providing build-time artifact preparation: variable normalization/validation (server, hostname, MAC, TFTP/NFS paths), kernel NFS root configuration, Docker mount handling, image customization (disable resize-filesystem, skip firstlogin wizard), TFTP directory staging, PXELINUX config generation, and hook invocation for downstream deployment.
Rootfs Handling for NFS
lib/functions/image/rootfs-to-image.sh
Added configurable ROOTFS_COMPRESSION (gzip/zstd/none) for NFS roots, selective archive generation, and optional rsync export of rootfs tree to ROOTFS_EXPORT_DIR with boot and virtual filesystem exclusions.
Build Framework Integration
lib/functions/configuration/main-config.sh
Conditional skipping of host filesystem compatibility check when NFS rootfs type is selected.
Netboot Documentation
extensions/netboot/README.md
Comprehensive guide documenting netboot extension payload, build-time variables/defaults, artifact hook, upstream U-Boot constraints, server-side configuration (TFTP/NFS layout, tftpd-hpa, systemd/firewall), DHCP configuration for common server implementations, deployment workflows, and troubleshooting guide.

Sequence Diagram(s)

sequenceDiagram
    participant Builder as Armbian Builder
    participant Ext as Netboot Extension
    participant KernelCfg as Kernel Config
    participant ImgGen as Image Generator
    participant TFTP as TFTP Staging
    participant Hook as netboot_artifacts_ready Hook

    Builder->>Ext: trigger extension (ROOTFS_TYPE=nfs)
    Ext->>Ext: validate & normalize variables<br/>(server, MAC, TFTP/NFS paths)
    Ext->>KernelCfg: configure NFS root support<br/>(IP_PNP, ROOT_NFS, NFS_FS, etc.)
    Ext->>ImgGen: customize image<br/>(disable resize, skip firstlogin)
    ImgGen->>ImgGen: build rootfs
    Ext->>ImgGen: handle ROOTFS_COMPRESSION<br/>(gzip/zstd/none)
    ImgGen->>ImgGen: generate compressed archive<br/>or export via rsync
    Ext->>TFTP: collect kernel, DTB, uInitrd<br/>to TFTP directory structure
    Ext->>TFTP: generate extlinux/PXELINUX<br/>config (default + per-MAC)
    Ext->>TFTP: construct nfsroot= param
    Ext->>Hook: invoke with artifact context<br/>(NETBOOT_TFTP_OUT, NETBOOT_PXE_FILE, etc.)
    Hook->>Hook: deploy to server
Loading
sequenceDiagram
    participant DHCP as DHCP Server
    participant Client as Client Device
    participant UBoot as U-Boot
    participant TFTP as TFTP Server
    participant NFS as NFS Server

    Client->>DHCP: request IP + PXE options
    DHCP->>Client: provide IP, siaddr, bootfile
    Client->>UBoot: load via PXE
    UBoot->>TFTP: load pxelinux.cfg/01-MAC<br/>or pxelinux.cfg/default
    TFTP->>UBoot: extlinux config
    UBoot->>TFTP: load kernel (Image/zImage)
    TFTP->>UBoot: kernel image
    UBoot->>TFTP: load DTB
    TFTP->>UBoot: device tree blob
    UBoot->>TFTP: load uInitrd (optional)
    TFTP->>UBoot: initramfs
    UBoot->>UBoot: construct kernel cmdline<br/>(root=/dev/nfs, nfsroot=, etc.)
    UBoot->>NFS: mount root filesystem<br/>via configured nfsroot path
    NFS->>Client: provide rootfs mount
    Client->>Client: boot kernel with NFS root
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 A netboot dream, now brought to life!
Through TFTP and NFS, no USB strife.
The Builder prepared the artifacts with care,
While U-Boot boots kernels floating in air.
With compression and hooks, the dance is complete—
Network boots have never been so neat!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a netboot extension for TFTP+NFS diskless boot, which is the primary purpose of the PR.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added 05 Milestone: Second quarter release size/large PR with 250 lines or more Needs review Seeking for review Hardware Hardware related like kernel, U-Boot, ... Framework Framework components Documentation Documentation changes or additions labels Apr 11, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@extensions/netboot/netboot.sh`:
- Around line 38-42: The function
extension_prepare_config__netboot_force_nfs_rootfs sets ROOTFS_TYPE too late (it
runs during do_extra_configuration) so NFS-specific branches in
do_main_configuration never see it; move the ROOTFS_TYPE assignment earlier by
ensuring extension_prepare_config__netboot_force_nfs_rootfs (or its logic) runs
before do_main_configuration—either call that function in the init/startup hook
that executes prior to main configuration (e.g., extension_init or top-level
script before do_main_configuration) or export/set declare -g ROOTFS_TYPE="nfs"
at script initialization so the global variable is in effect for
do_main_configuration and the NFS setup in
lib/functions/configuration/main-config.sh executes.
- Around line 147-149: The PXE staging copies ${MOUNT}/boot/uInitrd but never
references it in the generated extlinux.cfg, so U-Boot won't load the initramfs;
modify the netboot stanza generation to set an initrd_line variable when the
file exists (mirror how fdt_line is created — e.g. check for
"${MOUNT}/boot/uInitrd", set initrd_line="INITRD ${tftp_prefix_dir}/uInitrd")
and then include ${initrd_line} in the emitted PXE stanza alongside fdt_line so
the INITRD directive is present for U-Boot.

In `@extensions/netboot/README.md`:
- Around line 137-155: The README has multiple unlabeled fenced code blocks
(e.g., the directory tree block showing "/srv/netboot/" and other blocks around
lines 159-164, 171-175, 465-489, 544-547); update each triple-backtick fence to
include an appropriate info string (for example use sh, ini, or text as
appropriate) so markdownlint stops flagging them—locate the fences by searching
for the blocks that display the directory tree and configuration snippets and
add the matching language tag to each opening ``` line.

In `@lib/functions/image/rootfs-to-image.sh`:
- Around line 82-93: The rsync into ROOTFS_EXPORT_DIR can leave stale files
behind when the export tree is reused; update the rsync invocation in
rootfs-to-image.sh (the run_host_command_logged rsync call) to include --delete
(and optionally --delete-excluded) so files removed from the source are removed
from "${ROOTFS_EXPORT_DIR}" as well; add the flag either into $rsync_ea or
directly in the rsync command invocation to ensure exported NFS root mirrors the
built image.
- Around line 69-76: The archive creation pipeline (tar … | pv … |
${archive_filter} > "${ROOTFS_ARCHIVE_PATH}") must be guarded with pipefail so
failures in tar or pv aren't masked by a later stage; wrap that pipeline in a
shell context with set -o pipefail (or enable set -o pipefail locally before
running the pipeline) so a nonzero exit from tar or pv will cause the script to
fail and propagate the error from creating ROOTFS_ARCHIVE_PATH; update the block
around display_alert/ tar / pv / ${archive_filter} to ensure pipefail is active
for that pipeline.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fca3bef5-36a8-4aaa-81dd-645853e7579e

📥 Commits

Reviewing files that changed from the base of the PR and between fdef407 and 2393977.

📒 Files selected for processing (5)
  • config/templates/nfs-boot.cmd.template
  • extensions/netboot/README.md
  • extensions/netboot/netboot.sh
  • lib/functions/configuration/main-config.sh
  • lib/functions/image/rootfs-to-image.sh

@iav iav marked this pull request as draft April 11, 2026 23:50
iav added a commit to iav/armbian that referenced this pull request Apr 12, 2026
`nfs-root` is a new rootfs type distinct from the existing `nfs` hybrid
mode. Selecting it wires the `netboot` extension from the core
`ROOTFS_TYPE` dispatch in `do_main_configuration`, so callers no longer
need a separate `ENABLE_EXTENSIONS=netboot`. The legacy `nfs` branch
(kernel+DTB on local boot partition, `/` over NFS) is untouched — both
paths coexist until the hybrid mode's future is decided.

Core plumbing mirrors the `nfs` branch for all paths where local root
storage would be meaningless: partition layout skip
(`prepare_partitions`), archive/export gate and version suffix
(`rootfs-to-image.sh`), and the host-side filesystem compatibility
check in `main-config.sh`.

Extension hooks now key on `ROOTFS_TYPE=nfs-root` instead of guessing
from `nfs`, removing the `force ROOTFS_TYPE=nfs` shim that ran too
late relative to `do_main_configuration`.

Also folded in from CodeRabbit review on PR armbian#9656:
- pipefail around tar|pv|compressor so truncated archives no longer
  slip through on an intermediate stage failure
- `rsync --delete` on `ROOTFS_EXPORT_DIR` so stale files from a
  previous build don't linger in the NFS export tree
- explicit `INITRD` directive in extlinux when `uInitrd` is staged;
  U-Boot only loads an initramfs when the stanza names it
- README updated to document `ROOTFS_TYPE=nfs-root` as the single
  switch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rpardini
Copy link
Copy Markdown
Member

Very nice. With recent u-boot (2026.04, thanks to Kwiboo), one can enable LWIP networking stack for better TFTP performance (loading kernel and initramfs) -- there's also some TFTP Window Size stuff that can be tuned. U-boot with LWIP + u-boot's wget offers the best performance, but is not integrated in pxe or dhcp boot target AFAIK.

@iav
Copy link
Copy Markdown
Contributor Author

iav commented Apr 12, 2026

Thanks for the pointer! Let's get this merged first — iterating on something that works is the easy part.

Adds ROOTFS_TYPE=nfs-root — a new rootfs type for full network boot
where the only thing on the device's local storage is U-Boot itself.
The kernel, DTB, optional uInitrd and PXE config come from TFTP;
rootfs is mounted over NFS.

A new case branch in do_main_configuration auto-enables the netboot
extension, symmetric with existing fs-f2fs-support / fs-btrfs wiring.
The legacy ROOTFS_TYPE=nfs (hybrid: kernel on local storage, only /
over NFS) is untouched — both paths coexist.

extensions/netboot/netboot.sh hooks:
- extension_prepare_config: validate variables, compute defaults for
  NETBOOT_TFTP_PREFIX / NETBOOT_NFS_PATH (shared by
  LINUXFAMILY/BOARD/BRANCH/RELEASE, or per-host when NETBOOT_HOSTNAME
  is set), normalize NETBOOT_CLIENT_MAC to PXELINUX 01-<mac> form,
  fail fast on bad ROOTFS_COMPRESSION/ROOTFS_EXPORT_DIR combinations.
- custom_kernel_config: enable ROOT_NFS, NFS_FS, NFS_V3, IP_PNP,
  IP_PNP_DHCP so root=/dev/nfs ip=dhcp works without an initrd.
- post_customize_image: drop armbian-resize-filesystem.service
  (meaningless on NFS root) and /root/.not_logged_in_yet (the
  armbian-firstlogin interactive wizard blocks bring-up when there is
  no interactive console). armbian-firstrun.service stays — it only
  regenerates SSH host keys.
- host_pre_docker_launch: bind-mount ROOTFS_EXPORT_DIR into the build
  container when it lives outside ${SRC}.
- pre_umount_final_image: assemble the TFTP tree (Image/zImage, dtb/,
  uInitrd), write pxelinux.cfg/{default.example | 01-<mac>} with the
  right FDT/FDTDIR line and explicit INITRD directive when uInitrd is
  present, expose a netboot_artifacts_ready hook for userpatches.

Core plumbing (main-config.sh, partitioning.sh, rootfs-to-image.sh):
- nfs-root case branch in ROOTFS_TYPE dispatch enables the extension
- prepare_partitions skips root partition and SD-size sanity check
- check_filesystem_compatibility_on_host skipped for nfs-root
- ROOTFS_COMPRESSION=gzip|zstd|none with ROOTFS_EXPORT_DIR support
- pipefail around tar|pv|compressor pipeline
- rsync --delete on ROOTFS_EXPORT_DIR to prevent stale files
- ROOTFS_ARCHIVE_PATH exported for downstream hooks

Directory-based extension layout (extensions/netboot/) so the usage
guide (README.md) lives next to the code.

No console= in APPEND — hardcoding a baud breaks boards with
non-standard UART speeds; the kernel resolves console from DTB
/chosen/stdout-path, earlycon keeps early output.

Validated end-to-end on helios64 (Armbian 26.05 edge/resolute):
archive-workflow and tree-workflow both boot cleanly over TFTP+NFS
to a login prompt with no armbian-firstlogin wizard and no resize2fs
errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@iav iav force-pushed the enh/netboot-extension branch from a76e4b2 to fec99ac Compare April 12, 2026 17:14
@iav iav added the Work in progress Unfinished / work in progress label Apr 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

05 Milestone: Second quarter release Documentation Documentation changes or additions Framework Framework components Hardware Hardware related like kernel, U-Boot, ... Needs review Seeking for review size/large PR with 250 lines or more Work in progress Unfinished / work in progress

Development

Successfully merging this pull request may close these issues.

2 participants