Problem
node.Setup runs setupSecondaryNICs first (node/node.go:49 → node/links_linux.go:36). It returns an error on the first name in pool.json's secondaryNICs that has no link, so the daemon never reaches the bridge, sysctl, iptables or the DHCP server.
Scenario: a Volcengine node provisioned with seven ENIs records secondaryNICs: [eth1..eth7]. One ENI is detached out of band (quota action, console operation, or the InsufficientIpInSubnet cleanup docs/volcengine.md recommends). On the next restart netlink.LinkByName("eth2") fails, runDaemon returns, systemd restarts it, and the loop never ends. Six healthy ENIs and their pool IPs stay unused; every VM on the node loses its lease at expiry.
Two neighbouring code paths already treat the same condition as survivable: node/sysctl.go:39 warns and continues on a per-interface key, and cmd/adopt.go:67 filters the candidate list through node.PresentLinks. runDaemon (cmd/daemon.go:82) passes state.SecondaryNICs straight through.
Proposal
Filter cfg.SecondaryNICs through PresentLinks in node.Setup (or warn per missing link the way setupSysctl does) and keep the hard error only when none of the expected links is present. This relaxes a fail-fast startup check, which is why it is a decision rather than a fix.
Acceptance
With eth2 detached and eth1 present, cocoon-net daemon starts, logs the missing link at Warn, and serves DHCP on the remaining ENIs; with no expected link present it still fails.
Found in the 2026-09-21 whole-repo review round (branch review/whole-repo-2026-09-21). Filed as a behaviour question for the owner; no code change is included in the round PR.
Problem
node.SetuprunssetupSecondaryNICsfirst (node/node.go:49→node/links_linux.go:36). It returns an error on the first name inpool.json'ssecondaryNICsthat has no link, so the daemon never reaches the bridge, sysctl, iptables or the DHCP server.Scenario: a Volcengine node provisioned with seven ENIs records
secondaryNICs: [eth1..eth7]. One ENI is detached out of band (quota action, console operation, or theInsufficientIpInSubnetcleanupdocs/volcengine.mdrecommends). On the next restartnetlink.LinkByName("eth2")fails,runDaemonreturns, systemd restarts it, and the loop never ends. Six healthy ENIs and their pool IPs stay unused; every VM on the node loses its lease at expiry.Two neighbouring code paths already treat the same condition as survivable:
node/sysctl.go:39warns and continues on a per-interface key, andcmd/adopt.go:67filters the candidate list throughnode.PresentLinks.runDaemon(cmd/daemon.go:82) passesstate.SecondaryNICsstraight through.Proposal
Filter
cfg.SecondaryNICsthroughPresentLinksinnode.Setup(or warn per missing link the waysetupSysctldoes) and keep the hard error only when none of the expected links is present. This relaxes a fail-fast startup check, which is why it is a decision rather than a fix.Acceptance
With
eth2detached andeth1present,cocoon-net daemonstarts, logs the missing link at Warn, and serves DHCP on the remaining ENIs; with no expected link present it still fails.Found in the 2026-09-21 whole-repo review round (branch
review/whole-repo-2026-09-21). Filed as a behaviour question for the owner; no code change is included in the round PR.