test bridge state recovery
All checks were successful
Build and Deploy MITM Webserver / traffic_target (push) Successful in 1s
Build and Deploy MITM Webserver / build (push) Successful in 10s

This commit is contained in:
2026-03-09 16:02:47 +01:00
parent 665c0b4475
commit 6534f2c4fa
2 changed files with 17 additions and 1 deletions

View File

@@ -54,6 +54,7 @@ class BackendSettings:
bridge_bpf_build_dir: str bridge_bpf_build_dir: str
bridge_link_state_thread_join_timeout_seconds: float bridge_link_state_thread_join_timeout_seconds: float
bridge_link_state_recovery_holdoff_seconds: float bridge_link_state_recovery_holdoff_seconds: float
bridge_link_state_degraded_recheck_seconds: float
telemetry_process_stop_timeout_seconds: float telemetry_process_stop_timeout_seconds: float
telemetry_reader_join_timeout_seconds: float telemetry_reader_join_timeout_seconds: float
tshark_enabled: bool tshark_enabled: bool
@@ -96,6 +97,10 @@ def load_settings() -> BackendSettings:
"BACKEND_BRIDGE_LINK_STATE_RECOVERY_HOLDOFF_SECONDS", "BACKEND_BRIDGE_LINK_STATE_RECOVERY_HOLDOFF_SECONDS",
1.0, 1.0,
), ),
bridge_link_state_degraded_recheck_seconds=_env_float(
"BACKEND_BRIDGE_LINK_STATE_DEGRADED_RECHECK_SECONDS",
0.5,
),
telemetry_process_stop_timeout_seconds=_env_float("BACKEND_TELEMETRY_PROCESS_STOP_TIMEOUT_SECONDS", 3.0), telemetry_process_stop_timeout_seconds=_env_float("BACKEND_TELEMETRY_PROCESS_STOP_TIMEOUT_SECONDS", 3.0),
telemetry_reader_join_timeout_seconds=_env_float("BACKEND_TELEMETRY_READER_JOIN_TIMEOUT_SECONDS", 2.0), telemetry_reader_join_timeout_seconds=_env_float("BACKEND_TELEMETRY_READER_JOIN_TIMEOUT_SECONDS", 2.0),
tshark_enabled=_env_bool("BACKEND_TSHARK_ENABLED", True), tshark_enabled=_env_bool("BACKEND_TSHARK_ENABLED", True),

View File

@@ -76,6 +76,7 @@ class BridgeLinkStateWatcher:
self._suppressed_members: dict[str, bool] = {} self._suppressed_members: dict[str, bool] = {}
self._settle_deadlines: dict[str, float] = {} self._settle_deadlines: dict[str, float] = {}
self._all_clear_since: Optional[float] = None self._all_clear_since: Optional[float] = None
self._degraded = False
self._last_event_ts: Optional[float] = None self._last_event_ts: Optional[float] = None
self._last_error: Optional[str] = None self._last_error: Optional[str] = None
self._last_action: Optional[str] = None self._last_action: Optional[str] = None
@@ -126,6 +127,7 @@ class BridgeLinkStateWatcher:
"last_action": self._last_action, "last_action": self._last_action,
"suppressed_members": sorted(self._suppressed_members), "suppressed_members": sorted(self._suppressed_members),
"recovery_holdoff_seconds": self.recovery_holdoff_seconds, "recovery_holdoff_seconds": self.recovery_holdoff_seconds,
"degraded_recheck_seconds": settings.bridge_link_state_degraded_recheck_seconds,
"members": members, "members": members,
} }
@@ -188,6 +190,7 @@ class BridgeLinkStateWatcher:
if len(states) < 2: if len(states) < 2:
with self._lock: with self._lock:
self._degraded = False
self._all_clear_since = None self._all_clear_since = None
self._restore_suppressed_members(reason="bridge_has_fewer_than_two_members") self._restore_suppressed_members(reason="bridge_has_fewer_than_two_members")
return return
@@ -206,6 +209,7 @@ class BridgeLinkStateWatcher:
if failing_members: if failing_members:
with self._lock: with self._lock:
self._degraded = True
self._all_clear_since = None self._all_clear_since = None
self._suppress_other_members(states, failing_members) self._suppress_other_members(states, failing_members)
return return
@@ -213,6 +217,7 @@ class BridgeLinkStateWatcher:
if suppressed_snapshot: if suppressed_snapshot:
should_restore = False should_restore = False
with self._lock: with self._lock:
self._degraded = True
if self._all_clear_since is None: if self._all_clear_since is None:
self._all_clear_since = now self._all_clear_since = now
should_restore = now - self._all_clear_since >= self.recovery_holdoff_seconds should_restore = now - self._all_clear_since >= self.recovery_holdoff_seconds
@@ -225,6 +230,7 @@ class BridgeLinkStateWatcher:
return return
with self._lock: with self._lock:
self._degraded = False
self._all_clear_since = None self._all_clear_since = None
self._restore_suppressed_members(reason=reason) self._restore_suppressed_members(reason=reason)
@@ -234,7 +240,12 @@ class BridgeLinkStateWatcher:
with self._lock: with self._lock:
if self._suppressed_members and self._all_clear_since is not None: if self._suppressed_members and self._all_clear_since is not None:
deadline = self._all_clear_since + self.recovery_holdoff_seconds deadline = self._all_clear_since + self.recovery_holdoff_seconds
return max(0.0, deadline - time.time()) return max(
0.0,
min(deadline - time.time(), settings.bridge_link_state_degraded_recheck_seconds),
)
if self._degraded:
return settings.bridge_link_state_degraded_recheck_seconds
return None return None
def _wake_thread(self) -> None: def _wake_thread(self) -> None: