Optimize conntrack monitor time window.#1794
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the WAN “fallback connectivity” check that monitors conntrack -E updates, aiming to shorten average detection time by streaming output via child_process.spawn and terminating the monitor as soon as qualifying traffic is observed.
Changes:
- Replace the
exec(timeout conntrack | grep ...)pipeline with aspawn('sudo', ['conntrack', ...])stream parser that can stop early on first match. - Simplify conntrack monitoring window logic by removing adaptive timing and using a single
CONNTRACK_MONITOR_SEC_DEFAULTvalue (now 10s).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| child.stderr.on('data', () => {}); | ||
| child.on('error', () => finish(false)); |
There was a problem hiding this comment.
child.stderr is fully ignored, which makes it hard to diagnose common failure modes (e.g., sudo not permitted, conntrack missing, or kernel permissions). Capturing a small amount of stderr (or logging it at debug level) would make fallback behavior more observable and help distinguish “no traffic seen” from “monitor failed to run.”
| return new Promise((resolve) => { | ||
| const child = spawn('sudo', [ | ||
| 'conntrack', '-E', '-e', 'UPDATE', '--reply-dst', replyDst | ||
| ], { stdio: ['ignore', 'pipe', 'pipe'] }); |
There was a problem hiding this comment.
The new spawn/stream parsing + early-kill logic introduced here is behaviorally significant and currently has no targeted tests. Add unit tests that stub child_process.spawn to validate: resolves true on first matching line (public dst=), ignores private dst, handles stdout chunk/line splitting, resolves false on timeout/error/close, and terminates the child when finishing early to avoid lingering conntrack -E processes.
| const results = await Promise.all( | ||
| replyDsts.map(d => this._checkWanStatusByConntrackForReplyDst(d, monitorSec)) | ||
| replyDsts.map(d => this._checkWanStatusByConntrackForReplyDst(d, CONNTRACK_MONITOR_SEC_DEFAULT)) | ||
| ); | ||
| return results.some(Boolean); |
There was a problem hiding this comment.
Using Promise.all(...) here means _checkWanStatusByConntrack() will still wait for every per-IP conntrack monitor to finish/timeout, even if one replyDst already matched and resolved true. That largely negates the intended optimization (early exit) and can add up to CONNTRACK_MONITOR_SEC_DEFAULT delay to WAN checks. Consider resolving as soon as any monitor returns true (e.g., race/any on truthy) and cancelling the remaining children.
| // Process runs as pi; sudo/conntrack run as root so we can't kill via process.kill(-pgid). Use sudo pkill. | ||
| const pkill = spawn('sudo', [ | ||
| 'pkill', '-9', '-f', `conntrack -E -e UPDATE --reply-dst ${replyDst}` |
There was a problem hiding this comment.
sudo pkill -9 -f ...${replyDst} is risky here: pkill -f treats the pattern as a regex, so the dots in an IPv4 address will match any character and could kill unrelated conntrack -E monitors. It can also interfere with concurrent checks for the same replyDst by killing the other instance. Safer approach is to terminate by PID (e.g., sudo kill/sudo kill -9 using child.pid) or otherwise make the match exact/escaped and scoped to just this spawned process.
| // Process runs as pi; sudo/conntrack run as root so we can't kill via process.kill(-pgid). Use sudo pkill. | |
| const pkill = spawn('sudo', [ | |
| 'pkill', '-9', '-f', `conntrack -E -e UPDATE --reply-dst ${replyDst}` | |
| // Process runs as pi; sudo/conntrack run as root so we can't kill via process.kill(-pgid). Use sudo pkill on the child PID. | |
| const pkill = spawn('sudo', [ | |
| 'pkill', '-9', '-P', String(child.pid) |
4041083 to
7e4d4c9
Compare
|
Re-reviewed this PR (latest commit Overall direction (streaming + early match) is good, but I found a couple of correctness issues that should be fixed before merge. Critical Issues[plugins/interface/intf_base_plugin.js:1529] spawn('sudo', ['pkill', '-P', '-9', child.pid], ...)For Please change to a valid form (e.g. signal first, then Potential Bugs[plugins/interface/intf_base_plugin.js:1569] [plugins/interface/intf_base_plugin.js:1530] Performance Issues[plugins/interface/intf_base_plugin.js:56, 1570] Maintainability / Style[plugins/interface/intf_base_plugin.js:1542] Suggestions
|
use nodejs spawn + kill child when any data matched.