Skip to content

tunnel: improve startup resilience and diagnostics - #2438

Merged
openipc-ai merged 6 commits into
OpenIPC:masterfrom
usa-:improve-tunnel
Sep 18, 2026
Merged

openipc-ai merged 6 commits into
OpenIPC:masterfrom
usa-:improve-tunnel

Conversation

@usa-

@usa- usa- commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Problem

This change follows up on the problem described in #2406.

The current /usr/sbin/tunnel script starts vtund immediately and restarts it in a tight loop. If the network is not ready yet, there may be no default-route interface from which to obtain the camera identity and MAC address. The resulting VTun configuration is invalid and vtund exits with errors such as:

syntax error line 5
No hosts defined

The immediate restart loop can then repeatedly produce the same errors and quickly fill the 64 KB syslog ring, making other messages from the affected boot difficult or impossible to recover.

There are also several shell functions shared by wireguard and tunnel, but they were previously implemented only inside /usr/sbin/wireguard.

During testing I also observed an intermittent VTun startup failure:

Input/output error (5)

This is consistent with the race condition described in Red Hat Bugzilla #1462458, comment 26. VTun can attempt to write to the TUN/TAP device while the newly created interface is not yet administratively up, causing the write to /dev/net/tun to return EIO.

In the OpenIPC configuration, the interface is normally brought up by the up command from the VTun configuration. The failure is intermittent; after VTun is restarted, it usually does not occur again.

The new tunnel script works around this by configuring and bringing the tunnel interface up before starting vtund.

Hardware tested on

The changed scripts were tested for two days on remote cameras running:

  • Ingenic T31x
  • SigmaStar ssc337de
  • SigmaStar ssc378de (more than five cameras)

The testing covered normal startup conditions with the network and DNS already available.

I have not yet tested the failure/recovery cases where the network route or DNS resolution is unavailable when tunnel starts.

Evidence

Before:

When tunnel starts before the network is ready, vtund can be started
without a valid interface/MAC identity and exits with:

syntax error line 5
No hosts defined

The original script immediately starts vtund again, producing the same
errors repeatedly.

During testing, an intermittent VTun startup failure was also observed:

Input/output error (5)

After VTun was restarted, the error usually did not occur again.

After:

The new tunnel script waits for a default route and a valid MAC address
before generating the vtund configuration.

When a hostname is used for the VTun server, the script also waits until
the hostname can be resolved. Literal IPv4 addresses are accepted without
DNS resolution.

VTun restarts are paced instead of running in a tight loop.

The tunnel interface is explicitly configured and brought up before
vtund is started, avoiding the intermittent EIO startup condition
described above.

The normal startup path was tested for two days on T31x, ssc337de and
more than five ssc378de cameras.

The negative startup/recovery cases were not directly reproduced during this test period.

Scope

  • No kernel patches under general/package/all-patches/linux/ (those go to [OpenIPC/linux](https://github.com/OpenIPC/linux))
  • No files specific to a single retail camera model (those go to [OpenIPC/builder](https://github.com/OpenIPC/builder))
  • No probing or bring-up tooling (that goes to [OpenIPC/ipctool](https://github.com/OpenIPC/ipctool))
  • Nothing under general/overlay/ or in a shared load_<vendor> script hardcodes a value specific to my board
  • Package sources come from an OpenIPC repository, and any version bump keeps at least the specificity of the pin it replaces (a new package should pin a full 40-character SHA)
  • No LD_PRELOAD, and no binaries that cannot be rebuilt from source
  • New code is selected by a defconfig, so CI actually builds it

No package source or version is changed by this PR.

Changes

  • Moved shell functions shared by wireguard and tunnel into /usr/sbin/common.

  • Added /usr/sbin/kill_pid_file as a small executable wrapper so the kill_pid_file helper can also be invoked from commands launched by the VTun configuration.

  • Reworked /usr/sbin/tunnel to:

    • wait for a default route before trying to determine the camera identity;
    • wait for a valid MAC address;
    • wait for the VTun server to resolve when a hostname is used, while allowing literal IPv4 addresses;
    • avoid generating a known-invalid VTun configuration;
    • report which prerequisite is preventing startup;
    • use the common command wrapper for non-fatal command execution and diagnostics;
    • clean up a previous udhcpc instance using the common kill_pid_file helper;
    • explicitly configure and bring up the tunnel interface before starting vtund;
    • work around the intermittent VTun EIO startup race described in Red Hat Bugzilla #1462458, comment 26;
    • pace retries after startup failures instead of retrying in a tight loop;
    • clean up udhcpc when the VTun session goes down.
  • Changed /usr/sbin/wireguard to overwrite /tmp/wireguard.conf instead of appending to it, preventing duplicate configuration when the script is run manually more than once.

  • Changed the non-fatal path of the common command runner to return the actual command exit status, allowing callers such as tunnel to react to command failures.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Harden VTun startup and share tunnel script helpers

🐞 Bug fix ✨ Enhancement 🕐 20-40 Minutes

Grey Divider

AI Description

• Centralizes command execution and PID-file cleanup for WireGuard and VTun scripts.
• Delays VTun startup until route, identity, and server prerequisites are available.
• Preconfigures tunnel interfaces and paces restarts to prevent races and syslog flooding.
Diagram

graph TD
  WG["WireGuard Script"] -->|commands| COMMON["Common Helpers"]
  TUNNEL["Tunnel Controller"] -->|commands and cleanup| COMMON
  TUNNEL -->|preconfigure| IFACE["TUN Interface"] -->|identity| CFG["VTun Config"] -->|start| VTUND["VTun Daemon"] -->|session up| DHCP["DHCP Client"]
  VTUND -->|session down| WRAP["PID Wrapper"] -->|validated cleanup| COMMON
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Network-triggered supervised service
  • ➕ Starts only after network readiness events
  • ➕ Provides centralized lifecycle management and restart backoff
  • ➕ Avoids a detached, indefinitely polling shell process
  • ➖ Requires broader init-system or service-supervisor integration
  • ➖ May vary across supported embedded platforms
  • ➖ Substantially expands the scope beyond these scripts

Recommendation: Retain the polling and paced-restart approach for this PR because it is portable across the constrained BusyBox environment and directly addresses the boot races. A supervised, network-triggered service would be preferable only if OpenIPC adopts consistent service-management infrastructure across platforms.

Files changed (4) +150 / -96

Enhancement (1) +4 / -0
kill_pid_fileExpose PID-file cleanup as an executable command +4/-0

Expose PID-file cleanup as an executable command

• Adds a lightweight executable wrapper around the shared helper so generated VTun lifecycle commands can safely terminate udhcpc.

general/overlay/usr/sbin/kill_pid_file

Bug fix (1) +63 / -40
tunnelHarden VTun readiness, startup, and cleanup +63/-40

Harden VTun readiness, startup, and cleanup

• Waits for a default route, valid MAC identity, and hostname resolution before generating configuration. It preconfigures the TUN interface to avoid the VTun EIO race, safely cleans up udhcpc, and spaces restart attempts by ten seconds.

general/package/vtund-openipc/files/tunnel

Refactor (2) +83 / -56
commonAdd shared command and PID-file helpers +76/-0

Add shared command and PID-file helpers

• Introduces fatal and nonfatal command wrappers with consistent syslog diagnostics and output capture. Adds PID-file cleanup that verifies the process identity before signaling it and removing the file.

general/overlay/usr/sbin/common

wireguardAdopt shared helpers and overwrite generated configuration +7/-56

Adopt shared helpers and overwrite generated configuration

• Removes the local command wrapper in favor of the common implementation and explicitly uses nonfatal execution for interface and route setup. Generated WireGuard configuration now replaces the temporary file instead of appending to it.

general/overlay/usr/sbin/wireguard

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 18, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. All images ship a tunnel-only helper 📘 Rule violation ⚙ Maintainability
Description
general/overlay/usr/sbin/kill_pid_file adds an unconditional executable wrapper whose only runtime
use is the optional tunnel package's generated down command. Because general/overlay enters
every root filesystem, boards without the tunnel package still receive this executable and its
package-specific behavior.
Code

general/overlay/usr/sbin/kill_pid_file[R1-4]

+#!/bin/sh
+
+. /usr/sbin/common
+kill_pid_file "$@"
Evidence
Compliance rule 34 requires package-specific files to be delivered conditionally. The new wrapper is
in the unconditional overlay, while the tunnel configuration is the only shown consumer and belongs
to the optional VTun package.

CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files: CLAUDE.md: Use Conditional Late Overlays and Hooks for Package-Specific Files
general/overlay/usr/sbin/kill_pid_file[1-4]
general/package/vtund-openipc/files/tunnel[60-64]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new `kill_pid_file` executable is placed in the unconditional shared overlay even though only the optional VTun package invokes it.
## Fix Focus Areas
- general/overlay/usr/sbin/kill_pid_file[1-4]
- general/package/vtund-openipc/vtund-openipc.mk[20-28]
## Recommended Fix
Move the wrapper into `general/package/vtund-openipc/files/` and install it from `VTUND_OPENIPC_INSTALL_TARGET_CMDS` alongside `tunnel`, so it is present only when `BR2_PACKAGE_VTUND_OPENIPC` is selected.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Tunnel starts after interface setup fails ✓ Resolved 🐞 Bug ☼ Reliability
Description
The pre-start ifconfig call uses run_cmd_nonfatal, and its failure status is ignored before
vtund is launched. When that command cannot bring the interface up, VTun falls back to its
generated up command and remains exposed to the startup race this change is intended to prevent.
Code

general/package/vtund-openipc/files/tunnel[R69-70]

+		run_cmd_nonfatal "" "" ifconfig $vtund_iface hw ether $identity_mac mtu 1500 -multicast up # workaround for VTun bug described in https://bugzilla.redhat.com/show_bug.cgi?id=1462458#c26
+		vtund -n -f "$identity_cfg" "$identity_tid" "$vtund_server" >/dev/null 2>&1
Evidence
The script checks interface-creation failures and retries later, but it does not apply the same
control flow to the command that actually configures and raises the interface. It immediately
launches VTun after that unchecked failure, while the generated VTun configuration still contains
the original interface-up operation.

general/package/vtund-openipc/files/tunnel[36-39]
general/package/vtund-openipc/files/tunnel[58-60]
general/package/vtund-openipc/files/tunnel[69-70]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
VTun starts even when the pre-start interface configuration fails, defeating the startup-race workaround.
## Fix Focus Areas
- general/package/vtund-openipc/files/tunnel[69-70]
## Recommended Fix
Check the `ifconfig` result and skip starting `vtund` when it fails. Break to the paced outer retry loop, as already done for failures from `modprobe` and `tunctl`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

3. Invalid servers bypass resolution checks ✓ Resolved 🐞 Bug ≡ Correctness
Description
The ready predicate treats every server value beginning with [ as a literal address without
validating the remainder. A malformed value such as [invalid therefore skips nslookup, reaches
vtund, and is retried as a connection every ten seconds rather than remaining in the resolution
wait path.
Code

general/package/vtund-openipc/files/tunnel[R19-20]

+	echo "$vtund_server" | grep -qE '^\[|^((^|\.)(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){4}$' && return 0
+	nslookup "$vtund_server" >/dev/null 2>&1
Evidence
After obtaining the route and MAC, ready returns success for any string whose first character is
[, so the following lookup is not executed. Success exits the wait path and eventually passes the
unchecked server argument to VTun, whose exit is followed by another outer-loop attempt.

general/package/vtund-openipc/files/tunnel[14-20]
general/package/vtund-openipc/files/tunnel[23-35]
general/package/vtund-openipc/files/tunnel[69-76]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Malformed bracket-prefixed server values are accepted as literal addresses and bypass DNS resolution checks.
## Fix Focus Areas
- general/package/vtund-openipc/files/tunnel[19-20]
## Recommended Fix
Replace the broad `^\[` alternative with complete validation for the supported bracketed IPv6 representation, including a closing bracket and no trailing content. Only return success for a validated literal address; otherwise run `nslookup` and keep waiting on failure.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread general/overlay/usr/sbin/kill_pid_file Outdated
Comment thread general/package/vtund-openipc/files/tunnel Outdated
Comment thread general/package/vtund-openipc/files/tunnel Outdated
@usa-

usa- commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Why is the rule violation still reported if the corresponding issue was dismissed?

@openipc-ai openipc-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.

The design here is right and it works. I ran it on hardware rather than reading it, and nothing I found blocks it on correctness — the only thing standing in the way is that CI has never run (see the bottom).

Verified on a lab T31 camera

Copied the three files from bef20949 to /tmp on the board (the . /usr/sbin/common line rewritten to point at the temporary copy, so nothing persistent was touched) and ran tunnel directly.

Normal path, server 127.0.0.1:

$ sh /tmp/tt/tunnel 127.0.0.1
tunnel
script returned rc=0 immediately

$ ps w | grep -E 'vtund|tunnel'
19846 root      0:00 sh /tmp/tt/tunnel 127.0.0.1
19868 root      0:00 vtund[c]: 380146A2E638 connecting to 127.0.0.1

$ ifconfig tunnel
tunnel    Link encap:Ethernet  HWaddr 38:01:46:A2:E6:38
          UP BROADCAST  MTU:1500  Metric:1

The interface is up with the right MAC before vtund starts, so the EIO workaround does what it claims. The generated config is correct, including the quoted pid-file paths.

Unresolvable host, server no-such-vtun-host.invalid — one line, then silence for 45 s, no config written, vtund never started:

Sep 18 11:27:42 t31-sc2332 daemon.warn tunnel[19905]: waiting for a default route and for no-such-vtun-host.invalid to resolve

That is the fix working. Cleaned up afterwards; the board is back as it was.

All the no-hardware gates pass on the branch: test_shell_parse.sh, test_strip_shell_comments.sh, test_sysupgrade.sh, test_check_mac.sh, test_load_hisilicon.sh, test_excludes_report.sh, ci-matrix.py --self-test, lint-workflow-shell.py --self-test.

Four things that look like defects and are not

Recording these so nobody has to re-raise them:

  • modprobe tun || break on boards that build tun in. 31 defconfigs have CONFIG_TUN=y — all the sigmastar infinity6/6b0/6c/6e boards, xm510/xm530/xm550, rv1103/rv1106, v851s, hi3518ev300_ultimate — so there is no tun.ko. busybox modprobe reads modules.builtin as well as modules.dep, Buildroot installs it, and kernel/drivers/net/tun.ko is listed in it on ssc325 and ssc378de. Confirmed on two cameras: modprobe unix (built in) returns 0, modprobe definitely_no_such_module_xyz returns 1.
  • ifconfig … hw ether … up || break on the second and later passes, when the interface is already UP. tun_net_init sets IFF_LIVE_ADDR_CHANGE, so eth_prepare_mac_addr_change skips its netif_running → EBUSY branch. Checked in the 4.9.37/4.9.84/5.10.61 trees and confirmed on hardware (MAC changed on an up tap, rc=0).
  • The single quotes in -p '$udhcpc_pid' and kill_pid_file -9 '$udhcpc_pid' udhcpc. vtun's program statement with no leading PATH token leaves cmd->prog NULL, so run_cmd() in lib.c execs /bin/sh -c <args> rather than split_args + execv. The shell strips the quotes and searches $PATH, and /usr/sbin is on the boot PATH (checked /proc/<pid>/environ of a boot-started daemon). So the wrapper resolves and the paths are right.
  • Dropping the ^\[ branch. Correct: vtun 3.0.2 has no AF_INET6, sockaddr_in6 or getaddrinfo anywhere in its sources.

Findings

1. The flood most users will actually see is inside vtund, and this PR cannot reach it. With persist yes, vtund does not exit when the server is unreachable — client() loops internally on a hard-coded sleep(5) (there is no knob for it; the per-host timeout 10; is the connect timeout) and logs two daemon.info lines per attempt:

Sep 18 11:27:07 t31-sc2332 daemon.info vtund[19868]: Connecting to 127.0.0.1
Sep 18 11:27:07 t31-sc2332 daemon.info vtund[19868]: Connect to 127.0.0.1 failed. Connection refused(146)

24 lines/min, so the 64 KB ring S01syslogd -C64 sets up is overwritten in about half an hour, and the 10 s pacing never runs because vtund never returns to the shell. This PR fixes the config-error flood, which was the real root cause of #2319 (empty identity → bare { on line 5), and that is the right fix. It is just worth saying so on #2319 and #2406, so "vtun floods syslog" is not closed wholesale.

2. The syslog tag names a pid that has already exited. prog="${0##*/}[$$]" is evaluated before done &, and $$ is the parent shell's pid, not the background subshell's. In the run above the log line says tunnel[19905] while ps shows the loop as 19906. run_cmd_internal recomputes the same thing and has the same problem. Either drop [$$] or compute the tag inside the subshell.

3. A persistent setup failure still fills the ring, just ~50× slower. run_cmd_nonfatal logs unconditionally on every failure — measured 2 syslog lines per failed ifconfig, so 12 lines/min at the 10 s cadence. Given the PR's purpose it would be worth logging the first failure and then backing off (10 → 30 → 300) or staying quiet until the state changes, the way ready() already does so nicely.

4. ready()'s one warning never repeats, and does not say which precondition failed. A camera that waits forever logs a single line at boot and is then silent. It is also possible to wait forever on a route the awk does not parse — ip r printing default dev ppp0 scope link makes $5 equal scope, the MAC read fails, and ready never returns 0. Naming the failing precondition, and re-logging occasionally, would make that diagnosable.

5. general/overlay/usr/sbin/common is a sourced library living executable in a $PATH directory under a very generic name. Every camera gets a command called common that does nothing when run. /usr/share/openipc/common.sh at mode 0644 would say what it is. It also carries no comments at all — and since shipped scripts are comment-stripped at build time, a header explaining what may source it and what kill_pid_file's 251/252/253 mean costs nothing on the camera.

6. On where kill_pid_file belongs. Your "it is a generic utility, not VTun-specific" answer is reasonable, and there is a third option that fits this tree better than either side of that thread: general/overlay/usr/sbin/extutils is already the multi-call host for shared overlay helpers — check_mac, cli, get_mac, set_mac, netip_hash, sysinfo and ipctool are all symlinks into it. Adding kill_pid_file as an applet there gives you the generic utility you want without a new standalone wrapper, and sidesteps the "package-specific file in the unconditional overlay" objection.

To your question about why the violation is still reported: the dismissal struck the inline comment (it renders with strikethrough), but the summary comment posted at 09:05 is a separate, static comment that the bot does not rewrite afterwards. The two disagree by design.

7. Two behaviour changes are hidden under a "Refactor" title. In wireguard, ( … ) >>/tmp/wireguard.conf became { … } >, i.e. append became truncate. That is a correct fix — a manual re-run used to append a second copy, though at boot /tmp is empty so it never bit in the field — but nothing in the title or description says so. run_cmd's non-fatal path also now returns the real exit status instead of a bare return, which the new tunnel depends on. Both are improvements; they should just be visible. Related: the PR title becomes the squash subject, and this tree's style is area: lowercase imperative summary, so something like tunnel: wait for the network before writing a vtund config would fit better than "Refactor wireguard and tunnel scripts".

8. Small things.

  • All four touched files now end without a trailing newline; general/overlay/usr/sbin/wireguard had one before this PR.
  • Stray tab after shift in kill_pid_file.
  • tunctl's success output now reaches the boot console — it prints the interface name, and run_cmd_nonfatal echoes captured output on success when no variable is given. The old script had >/dev/null 2>&1.
  • The # OpenIPC.org | v.20230212 / by Igor Zalatov header was dropped from tunnel, while the sibling tapip in the same package keeps its equivalent. The # Busybox applets: line was useful documentation too — the script now additionally needs grep, logger, nslookup, ifconfig, kill and rm.
  • The comment on the ifconfig line is a trailing comment, so strip-shell-comments.awk leaves it in the shipped file. A full-line comment above the command would be stripped at build and cost the camera nothing.

Before this can merge

Every workflow on bef20949 is sitting in action_required — this is a fork PR whose runs a maintainer has never approved, so there is no CI on it at all yet. general/overlay/usr/sbin/common widens the matrix to all 99 boards, which is right for a file that enters every image (about +684 bytes compressed). I am approving the runs now; it needs to go green before merge.

One more piece of housekeeping: #2406 is a draft of mine covering the same ground in a single file. If this lands, that one should be closed in its favour.

@usa- usa- changed the title Refactor wireguard and tunnel scripts tunnel: improve startup resilience and diagnostics Sep 18, 2026
@usa-

usa- commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Regarding finding 4:

The ip r | awk '/default/ {print $5}' logic is unchanged from the original tunnel script, so this PR does not make that behavior less robust or introduce the default dev ... edge case.

The changes to ready() only add specific diagnostics for the failed prerequisite and retry backoff, so a persistent failure is no longer logged only once and then left silent.

Regarding findings 5 and 6:

Would you be OK with moving both the shared functions currently in /usr/sbin/common and kill_pid_file into the existing extutils mechanism?

extutils is already used as a common multi-call utility for shared /usr/sbin functionality, so this would let us remove both separate files and make kill_pid_file another generic extutils applet.

Regarding finding 8:

Very little of the original tunnel implementation remains, so I don't think the old author attribution is appropriate for the rewritten script.

Is the # Busybox applets: line an actual repository requirement or convention for scripts installed under /usr/sbin/? I could not find it consistently used across the other package scripts.

I will also clean up the minor formatting issues mentioned in this finding, such as trailing newlines and whitespace.

Regarding the new commit:

Could you please review the current version of the PR?

@openipc-ai

Copy link
Copy Markdown
Collaborator

Rebased onto master and CI approved. #2440 landed as 947a366, so gk7205v300_lite now has 84 KB of headroom instead of zero and the size failure this PR was hitting is gone. The rebase was a pure replay — no conflicts, no file overlap, your four commits unchanged and still yours.

For the record, since it was the reason this PR went red rather than anything you wrote: both gk7205v300_lite and hi3516ev300_lite were already over cap on master. gk7205v300_lite finished the 2026-09-17 build at 5119.54 KB of 5120 with the "0 KB left" warning firing, and #2421's lesson is exactly this — a board at zero headroom goes red on the next unrelated PR, not the one that pushed it there. Your ~620 bytes of overlay was that next PR.

The ecb9dd35 changes all look right to me:

  • read_subshell_pid reading field 1 of /proc/self/stat is a neat fix — read is a builtin and the redirect doesn't fork, so /proc/self resolves to the subshell that will actually be doing the logging. Tags now name a live process.
  • The backoff on both loops is the substantive one. The ready wait and the restart loop each climb 10 → 300 s, and ready naming which precondition failed means a camera that waits forever now says why.
  • Moving the bugzilla reference to its own line above the command means strip-shell-comments.awk removes it at build time, so the URL costs the camera nothing. Trailing newlines and the stray tab are all cleared.

Three small things left, none of which need to hold this up:

  1. tunnel:97 is a whitespace-only line (tabs). I left it alone rather than touch your commit during the rebase.
  2. restart_delay resets on any vtund return, not just a healthy one. restart_delay=$delay_start runs unconditionally after the vtund call, so a vtund that exits immediately would still be restarted every 10 s with no backoff — the one path where the original tight-loop shape could partly survive. In practice a valid config plus persist yes means it shouldn't exit at all, so this is theoretical; gating the reset on the session having lasted a while would close it.
  3. warning "starting the tunnel to $vtund_server" logs a success at daemon.warn. It was daemon.info before.

Still open from the earlier review and worth a maintainer's opinion rather than yours: where /usr/sbin/common should live (a sourced library, executable, in a $PATH directory, under a name as generic as common), and whether kill_pid_file is better as an extutils applet — check_mac, cli, get_mac, set_mac, netip_hash and sysinfo are already symlinks into that one multi-call script, which is the tree's existing answer to "shared overlay helper".

The full 99-board matrix is running now — the overlay file reaches every image, so ci-matrix.py widens to everything. That takes a while.

@openipc-ai

Copy link
Copy Markdown
Collaborator

Ran 3c4871ce on a camera — a lab T31 (t31-sc2332), the three files copied to /tmp with the . /usr/sbin/common line repointed at the temporary copy so nothing persistent was touched. Cleaned up afterwards.

The backoff works, and the pid fix works. Unresolvable server, warnings at increasing intervals, and note the tag:

Sep 18 13:51:50 t31-sc2332 daemon.warn tunnel[21928]: Unable to resolve the VTun server address
Sep 18 13:52:00 t31-sc2332 daemon.warn tunnel[21928]: Unable to resolve the VTun server address
Sep 18 13:52:20 t31-sc2332 daemon.warn tunnel[21928]: Unable to resolve the VTun server address
Sep 18 13:52:50 t31-sc2332 daemon.warn tunnel[21928]: Unable to resolve the VTun server address
Sep 18 13:53:31 t31-sc2332 daemon.warn tunnel[21928]: Unable to resolve the VTun server address

$ ps w | grep tunnel
21928 root      0:00 sh /tmp/tt/tunnel no-such-vtun-host.invalid

10 s, 20 s, 30 s, 41 s — climbing as intended. And tunnel[21928] is the pid ps shows. On bef20949 the same test logged tunnel[19905] while ps showed 19906, so read_subshell_pid does what it set out to do. No config was written and vtund never started, which is the point of the gate.

Normal path, literal 127.0.0.1:

$ sh /tmp/tt/tunnel 127.0.0.1
tunnel
$ ps w
22019 root      0:00 sh /tmp/tt/tunnel 127.0.0.1
22041 root      0:00 vtund[c]: 380146A2E638 connecting to 127.0.0.1
$ ifconfig tunnel
tunnel    Link encap:Ethernet  HWaddr 38:01:46:A2:E6:38
          UP BROADCAST  MTU:1500  Metric:1

Interface up with the right MAC before vtund starts, so the EIO workaround is doing its job, and the generated down block comes out correctly quoted:

	down {
		program "kill_pid_file -9 '/tmp/udhcpc-tunnel.pid' udhcpc";
		ifconfig "tunnel down";
	};

To be clear about what this is and is not: a T31 exercising the scripts, not any of the SoCs in your test matrix, and not a sysupgrade-flashed image. It does not replace your two days on T31x/ssc337de/ssc378de — it covers the negative paths you said you had not reproduced.

@usa-

usa- commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

So at this point, are we just waiting for the maintainer's opinion on where common and kill_pid_file should live?

Personally, I’m leaning towards moving both of them into extutils.

@openipc-ai openipc-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.

Green across all 99 boards, including gk7205v300_lite and hi3516ev300_lite, which needed #2440 first.

Everything actionable from the review is addressed across ecb9dd35 and 66ba0112: the pid the syslog tag names, backoff on both the readiness wait and the restart loop, ready saying which precondition failed, the restart-delay reset gated on vtund actually exiting cleanly, the informational line moved back to daemon.info, and the comment placed where strip-shell-comments.awk will take it out of the shipped file. Verified the revised script on a lab T31 — backoff climbing 10/20/30/41 s, and the tag matching the ps pid.

Two things stay open and are mine to carry, not yours: where /usr/sbin/common should live, and whether kill_pid_file belongs in extutils. Both are placement questions about files this PR introduces correctly; neither is worth another round here.

Worth restating for anyone reading #2319 later: this fixes the flood caused by an invalid generated config, which was the actual root cause — the empty identity writing a bare { on line 5. It does not touch the other flood, vtund's own persist yes reconnect, which loops on a hard-coded sleep(5) in client.c and logs two daemon.info lines per attempt whenever the server is unreachable. That one is inside vtund and out of scope here.

Thanks for the quick turnaround on the review points.

@openipc-ai
openipc-ai merged commit 49908b5 into OpenIPC:master Sep 18, 2026
117 checks passed
@usa-
usa- deleted the improve-tunnel branch September 19, 2026 08:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants