Robust interface detection — retry fallback chain for headless boot (#206)

Fixes interface auto-detection failures on Pi Zero 2W where wlan0 doesn't exist
at boot. Implementation:

- Added detect_interface_with_retry() function with 3x retry fallback chain
- Config-supplied interface preferred, then /proc/net/route, then UP interface
- Exponential backoff: 5s, 10s, 20s delays between retries
- Filters excluded prefixes: lo, tailscale*, wg*, tun*, docker*, veth*, br-*
- Used in Engine.__init__(), PacketCapture.start(), MacManager.start()
- Full test coverage: 10 tests for detection, backoff, filtering

Addresses issue where network stack initializes after boot and interfaces
become available after 5-10 second delay.
This commit is contained in:
Cobra
2026-04-08 20:58:43 -04:00
parent 6f421511de
commit 245731e73b
6 changed files with 235 additions and 8 deletions
+9 -4
View File
@@ -24,7 +24,7 @@ from typing import Optional, Type
from core.bus import EventBus, Event
from core.state import StateManager
from modules.base import BaseModule
from utils.networking import get_primary_interface
from utils.networking import detect_interface_with_retry
logger = logging.getLogger("sensor.engine")
@@ -240,12 +240,17 @@ class Engine:
self._scope = config.get("scope", {})
self._phase = config.get("engagement_phase", {}).get("mode", "passive_only")
# Resolve "auto" interface to actual interface name
# Resolve "auto" interface to actual interface name with retry fallback
if self.config.get("network", {}).get("primary_interface") == "auto":
actual_iface = get_primary_interface()
actual_iface = detect_interface_with_retry(
max_retries=3,
retry_delay=5,
exponential=True,
config_interface=None
)
if actual_iface:
self.config.setdefault("network", {})["primary_interface"] = actual_iface
logger.debug("Resolved auto interface to: %s", actual_iface)
logger.info("Resolved auto interface to: %s (with retry)", actual_iface)
self.capture_bus = None
self._lock = multiprocessing.Lock()
logger.info("Engine initialized (tier=%s, phase=%s)", self._tier, self._phase)