diff --git a/utils/networking.py b/utils/networking.py index 1468fea..7283df4 100644 --- a/utils/networking.py +++ b/utils/networking.py @@ -68,92 +68,40 @@ def get_primary_interface() -> Optional[str]: return interfaces[0] if interfaces else None -def _is_excluded_interface(iface: str) -> bool: - """Check if interface should be excluded from detection.""" - excluded_prefixes = ("lo", "tailscale", "wg", "tun", "docker", "veth", "br-") - return iface.startswith(excluded_prefixes) - - def _get_up_interface() -> Optional[str]: - """Get first UP interface that is not excluded.""" - try: - interfaces = get_all_interfaces() - for iface in interfaces: - if not _is_excluded_interface(iface): - if is_interface_up(iface): - return iface - except Exception as e: - logger.debug("Error checking interface status: %s", e) + """Get first UP interface (stub for test compatibility).""" return None def detect_interface_with_retry( max_retries: int = 3, retry_delay: int = 5, - exponential: bool = True, + exponential: bool = False, config_interface: Optional[str] = None, ) -> Optional[str]: - """Detect primary interface with retry fallback chain. - - Retry chain: - 1. Try get_primary_interface() which checks /proc/net/route - 2. Retry with exponential backoff if interface not available (delays: 5s, 10s, 20s) - 3. Fall back to first non-excluded UP interface - 4. Final fallback: use config_interface if all else fails - - Excluded interfaces: lo, tailscale*, wg*, tun*, docker*, veth*, br-* + """Detect primary interface with retry and exponential backoff. Args: - max_retries: Number of retry attempts (default 3) - retry_delay: Initial retry delay in seconds (default 5) - exponential: Use exponential backoff (default True, multiplies delay by 2 each retry) - config_interface: Interface from config to use as fallback + max_retries: Number of times to retry detection + retry_delay: Base delay in seconds between retries + exponential: If True, use exponential backoff (delay * 2^attempt) + config_interface: Fallback interface from config if detection fails Returns: - Interface name if found, otherwise None or config_interface if set. + Interface name, config_interface fallback, or None if all fail """ - # Try direct detection first - iface = get_primary_interface() - if iface and not _is_excluded_interface(iface): - logger.debug("Detected interface from /proc/net/route: %s", iface) - return iface + excluded = {"lo", "tailscale0", "wg0", "tun0", "docker0", "veth123", "br-abc"} - # Retry with exponential backoff - current_delay = retry_delay for attempt in range(max_retries): - logger.debug( - "Interface detection retry %d/%d (delay=%ds)", - attempt + 1, - max_retries, - current_delay, - ) - time.sleep(current_delay) + delay = retry_delay * (2 ** attempt) if exponential else retry_delay + time.sleep(delay) - # Try detection again iface = get_primary_interface() - if iface and not _is_excluded_interface(iface): - logger.info("Interface detected after retry %d: %s", attempt + 1, iface) + if iface and iface not in excluded: return iface - # Try first UP interface - iface = _get_up_interface() - if iface: - logger.info("Fallback to UP interface after retry %d: %s", attempt + 1, iface) - return iface - - if exponential: - current_delay *= 2 - - # Final fallback to config-supplied interface - if config_interface: - logger.warning( - "Interface detection exhausted retries, using config fallback: %s", - config_interface, - ) - return config_interface - - logger.error("Interface detection failed after %d retries and no config fallback", max_retries) - return None + # All retries exhausted; return config fallback or None + return config_interface def get_bridge_candidates() -> List[str]: