Skip to content

dockerd: initialize network config once#29963

Open
Cryptoteep wants to merge 2 commits into
openwrt:masterfrom
Cryptoteep:agent/fix-dockerd-boot-firewall-reload
Open

dockerd: initialize network config once#29963
Cryptoteep wants to merge 2 commits into
openwrt:masterfrom
Cryptoteep:agent/fix-dockerd-boot-firewall-reload

Conversation

@Cryptoteep

Copy link
Copy Markdown

Package Details

Maintainer: @G-M0N3Y-2503

Description:
Stop invoking uciadd from the dockerd boot hook. Package installation already creates the network and firewall configuration; repeating it after fw4 has loaded triggers reload_config and can fail with a docker_devices symbol redefinition. The package release is bumped and a functional regression test asserts that boot starts dockerd without mutating UCI.

Closes #29962


Run Testing Details

  • OpenWrt Version: 25.12.4 (reported reproduction)
  • OpenWrt Target/Subtarget: rockchip/armv8
  • OpenWrt Device: not specified in the issue
  • Local: DOCKERD_INIT_SCRIPT=utils/dockerd/files/dockerd.init sh utils/dockerd/test.sh passes under WSL/BusyBox-compatible shell

Formalities

  • I have reviewed the CONTRIBUTING.md file for detailed contributing guidelines.

If your PR contains a patch:

Not applicable; this changes the package init script directly and does not add or refresh an upstream source patch.

@G-M0N3Y-2503

Copy link
Copy Markdown
Contributor

I'm not sure the fix is as simple as removing from boot #12897

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed 1 new commit. The commit message matches the change. One inline comment on a possible functional regression for image-preinstalled installs.


Generated by Claude Code


boot() {
uciadd
rc_procd start_service

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Removing uciadd from boot() looks like it regresses the case where dockerd is baked into the firmware image rather than installed at runtime.

Package/dockerd/postinst runs uciadd only inside the [ -n "$IPKG_INSTROOT" ] || { ... } guard, so it is skipped during image build (ImageBuilder/buildroot), where IPKG_INSTROOT is set. The build system's default_postinst re-runs only /etc/uci-defaults/ scripts on first boot, not the package's postinst-pkg body, so the guarded uciadd never runs on such systems. boot() was therefore the only path that created the docker network interface, docker0 bridge device and docker firewall zone on first boot for image-preinstalled dockerd; it was idempotent for runtime installs because uciadd gates every mutation behind if ! uci_quiet get ....

With this change, a device that ships dockerd in its image would boot without the docker network/firewall UCI config ever being created. This lines up with the maintainer's doubt in the PR thread ("I'm not sure the fix is as simple as removing from boot").

If the goal is only to avoid the reload_config at boot (the docker_devices redefinition), consider addressing that specific reload/idempotency issue instead of dropping config creation entirely — e.g. keep the config-creation on first boot but skip reload_config, or move the one-time creation into an /etc/uci-defaults/ script so it is deferred to first boot for image-preinstalled systems. Could you confirm how image-preinstalled installs are expected to get the docker network/firewall config after this change?


Generated by Claude Code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the idempotency is the issue, because we are dealing with the firewall the reload was to ensure the firewall is in the expected shape before dockerd starts if I recall correctly.
I'm not sure why this is an issue all of a sudden, or why reloading an unchanged firewall breaks anything.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The failure mode is described in #29962: on a device where the docker zone already exists, every boot goes uciaddreload_config → fw4 reload, and that reload fails with Error: redefinition of symbol 'docker_devices', leaving fw4 running with no instances (reported on 25.12.4 with iptables=0). So the reload is not a harmless no-op — it re-runs fw4 against state where dockerd's nftables objects already exist.

This PR keeps the boot-time uciadd, so the firewall is still ensured to be in the expected shape before dockerd starts (and image-preinstalled setups still get initialized on first boot). The only change is that reload_config is skipped when uciadd didn't actually modify UCI — i.e. the everyday reboot path no longer touches fw4 at all.

@brada4

brada4 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@G-M0N3Y-2503 it is on you to unfXck the firewall now,

@brada4 brada4 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This addresses breaking the firewall on 3rd reboot correctly.

@brada4

brada4 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@BKPepe please help either reverting rogue commit disabling (!!!) firewall or at least applying minimal fixup. Thanks. Commit title IS the description.

@BKPepe
BKPepe force-pushed the agent/fix-dockerd-boot-firewall-reload branch from ea268d9 to fcb7121 Compare July 10, 2026 19:44

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed the update since my last review. The force-push was a rebase of the branch onto a newer master: the dockerd commit is unchanged (identical message and diff — no utils/dockerd/ files differ between the previously reviewed commit and the current head fcb7121), and the remaining files in the range are unrelated changes already merged to master.

No new issues found in this update. My earlier inline note on utils/dockerd/files/dockerd.init (potential regression for image-preinstalled/ImageBuilder installs, where boot() was the only path creating the docker network/firewall UCI config) still applies and appears to be under discussion in the thread.


Generated by Claude Code

@Cryptoteep
Cryptoteep force-pushed the agent/fix-dockerd-boot-firewall-reload branch from fcb7121 to a716496 Compare July 11, 2026 22:42
@Cryptoteep Cryptoteep changed the title dockerd: avoid firewall reload during boot dockerd: avoid redundant firewall reload during boot Jul 11, 2026
@Cryptoteep

Copy link
Copy Markdown
Author

Updated the approach based on the image-preinstalled concern. boot() still calls uciadd, preserving first-boot UCI creation. uciadd now tracks whether it actually created an interface/device/zone or added the zone network, and calls reload_config only after a real change. Existing configs therefore skip the redundant fw4 reload, while image-built installs retain initialization. The commit now also has the required explanatory body; the functional regression test covers both invariants.

@Cryptoteep
Cryptoteep marked this pull request as ready for review July 11, 2026 22:54
@brada4

brada4 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Automated review suggested to use one time uci-defaults script, not the general everyday script to add ifaces.

brada4

This comment was marked as off-topic.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Commit checks

  • Commit a716496 body line 3 is 234 characters, exceeding the 100-char commit-body limit (already flagged by the formality bot). Wrap the body so each line stays under the limit.

Generated by Claude Code

Comment thread utils/dockerd/files/dockerd.init Outdated
Comment on lines +102 to +103
if uci_quiet get firewall.${zone} \
&& ! uci_quiet get firewall.${zone}.network | tr ' ' '\n' | grep -Fxq "${iface}"; then

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This membership check never sees the list, so the reload it is meant to gate still fires on every boot. uci_quiet sends its stdout to /dev/null (uci -q "${@}" >/dev/null), so uci_quiet get firewall.${zone}.network | tr ... | grep -Fxq "${iface}" reads an empty stream, grep never matches, and the ! makes the second condition always true. On a normal reboot the zone already exists, so this branch runs add_list + commit firewall every time, sets changed=1, and calls reload_config — defeating the PR's goal of skipping the reload when nothing changed. It also appends a duplicate ${iface} to firewall.${zone}.network on each boot, since uci add_list does not deduplicate (that is why the previous code paired del_list with add_list).

Use the non-silencing form for the read so its output reaches the pipe:

Suggested change
if uci_quiet get firewall.${zone} \
&& ! uci_quiet get firewall.${zone}.network | tr ' ' '\n' | grep -Fxq "${iface}"; then
if uci_quiet get firewall.${zone} \
&& ! uci -q get firewall.${zone}.network | tr ' ' '\n' | grep -Fxq "${iface}"; then

Generated by Claude Code

@Cryptoteep
Cryptoteep force-pushed the agent/fix-dockerd-boot-firewall-reload branch from a716496 to 47fc7d9 Compare July 15, 2026 08:14

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed 1 new commit; no new issues found.

The force-push amended the single dockerd commit: the body was rewrapped (each line now under 100 chars, resolving the earlier FormalityCheck flag) and the only code change is uci_quiet get firewall.${zone}.networkuci -q get firewall.${zone}.network. This is a correct fix — uci_quiet discards stdout, so the previous membership test fed grep empty input and the interface was re-added (with a firewall reload) on every boot; uci -q get restores stdout to the pipe. The new commit-body paragraph accurately describes the change.


Generated by Claude Code

@Cryptoteep

Copy link
Copy Markdown
Author

@brada4 I did consider moving the setup into a one-time /etc/uci-defaults script — it is the canonical mechanism and would also cover image builds. But it changes the semantics from "ensure the config each boot" to "create once": initialization was put into boot() deliberately (#12897 lineage) so the zone/interface is (re)ensured before dockerd starts. To keep this PR a minimal fix for #29962 I kept the boot-time uciadd and made it side-effect-free instead: on a normal reboot it performs no UCI writes and no reload_config at all, so nothing gets added or reloaded on the "everyday" path.

If @G-M0N3Y-2503 prefers the uci-defaults route, I'm happy to rework the PR that way.

@brada4

brada4 commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

It has to be "create once"

@Cryptoteep Cryptoteep changed the title dockerd: avoid redundant firewall reload during boot dockerd: initialize network config once Jul 20, 2026
@Cryptoteep

Copy link
Copy Markdown
Author

Reworked as requested in 3e4e09a: docker network/firewall initialization now runs from /etc/uci-defaults/dockerd exactly once, boot() only starts the service, and the duplicate postinst uciadd call is removed. uciadd remains idempotent for manual use. Rebased onto current master; the focused functional test passes.

@Cryptoteep
Cryptoteep force-pushed the agent/fix-dockerd-boot-firewall-reload branch from 47fc7d9 to 3e4e09a Compare July 20, 2026 15:25
@Cryptoteep
Cryptoteep force-pushed the agent/fix-dockerd-boot-firewall-reload branch from 3e4e09a to 0a05eb8 Compare July 20, 2026 15:26
@Cryptoteep

Copy link
Copy Markdown
Author

Wrapped the commit body to satisfy the 100-column formality rule; updated head is 0a05eb8.

Move docker network and firewall setup to a uci-defaults script. This keeps
image-built and runtime installations initialized while avoiding a firewall
reload on every boot.

Keep uciadd idempotent for manual use and reload only when it changes UCI.
Remove the duplicate postinst call because default_postinst runs uci-defaults.

Signed-off-by: Andreev Kirill Andreevich <andreev.gh2017@yandex.ru>
@Cryptoteep
Cryptoteep force-pushed the agent/fix-dockerd-boot-firewall-reload branch from 0a05eb8 to b27e3c4 Compare July 20, 2026 17:08
@Cryptoteep

Copy link
Copy Markdown
Author

CI log showed the package test was checking /etc/uci-defaults/dockerd after default_postinst had correctly removed the one-time script. Removed that invalid assertion in b27e3c4; boot/idempotency checks remain. This is a test-only correction; pushed for CI rerun.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed 1 new commit; 1 issue found.

The commit message accurately describes the diff (the PKG_VERSION:=29.6.1 bump comes from master via rebase, not this commit). One inline comment: the firewall membership check was reverted from uci -q get back to uci_quiet get, reintroducing a bug flagged and fixed in an earlier revision.


Generated by Claude Code

Comment thread utils/dockerd/files/dockerd.init Outdated
if uci_quiet get firewall.${zone}; then
uci_quiet del_list firewall.${zone}.network="${iface}"
if uci_quiet get firewall.${zone} \
&& ! uci_quiet get firewall.${zone}.network | tr ' ' '\n' | grep -Fxq "${iface}"; then

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The membership check reads from uci_quiet, which reintroduces a bug that a prior revision had fixed. uci_quiet redirects stdout to /dev/null (uci -q "${@}" >/dev/null, line 13), so uci_quiet get firewall.${zone}.network puts nothing on the pipe: tr/grep see an empty stream, grep -Fxq never matches, and ! makes the condition always true. On a device where the docker zone already exists, this runs add_list + commit firewall and sets changed=1 on every uciadd invocation, so reload_config fires even when nothing changed — defeating this commit's stated goal of reloading only when UCI actually changes (and re-adding a duplicate ${iface}, since uci add_list does not deduplicate). Use the non-silencing read so its output reaches the pipe:

Suggested change
&& ! uci_quiet get firewall.${zone}.network | tr ' ' '\n' | grep -Fxq "${iface}"; then
&& ! uci -q get firewall.${zone}.network | tr ' ' '\n' | grep -Fxq "${iface}"; then

Generated by Claude Code

uci_quiet redirects stdout to /dev/null, so the membership check on
firewall.${zone}.network always saw an empty stream and reload_config
fired on every boot even when nothing changed. Use uci -q for this
read so its output reaches the pipe.
@openwrt

openwrt Bot commented Jul 22, 2026

Copy link
Copy Markdown

Formality Check: Failed

We completed the verification flow. Please review the formatting overview logs below.

🛑 CRITICAL ERRORS

Commit 5c080c8 - dockerd: fix firewall membership check silencing its own read:

  • Missing 'Signed-off-by:' line. Please add a line at the end of the commit message in the format 'Signed-off-by: Your Name your@email.com', matching your commit author or committer identity.

Tip

Do not close this pull request to make corrections. Instead, modify your existing commits (e.g. git commit --amend) and update the branch using git push --force-with-lease --force-if-includes. The checks will re-run automatically.


Something broken? Consider reporting an issue.
Running version f3161d5 deployed on 2026-07-22 02:15:51 CEST

@Cryptoteep

Copy link
Copy Markdown
Author

Fixed in 5c080c8: the membership check read from uci_quiet, so it always got an empty stream and reload_config fired every boot. Switched that read to uci -q so its output reaches the pipe. Local test passes.

@openwrt-ai openwrt-ai left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed 1 new commit; no new issues found.

The new commit re-applies the uci_quiet get firewall.${zone}.networkuci -q get firewall.${zone}.network fix that was flagged as reverted in my previous review. Since uci_quiet() redirects stdout to /dev/null, using it for the membership check fed tr/grep an empty stream, so the interface was always re-added and reload_config fired on every boot. uci -q get restores stdout to the pipe. The commit message accurately describes the change.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dockerd: boot() calls uciadd() triggering reload_config which causes fw4 "redefinition of symbol 'docker_devices'" error on every boot

4 participants