feat(obs): distinguish one-way broadcast flow

The client previously reported "Broadcast traffic flowing" as soon as either
broadcast TX or RX was nonzero. During the MVP DHCP/ARP proof, one-way
broadcast is useful but weaker evidence than bidirectional broadcast.

Keep the existing healthy message for two-way broadcast, but report
outbound-only broadcast as a warning that the client is still waiting for a LAN
broadcast reply, and report inbound-only broadcast separately. This makes the
Windows client status lines more precise when DHCP is stuck.

Test Plan:
- cargo test -p lanparty-obs
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
- git diff --cached --check

Refs: MVP Windows DHCP diagnostics
This commit is contained in:
2026-05-22 06:58:20 +02:00
parent ca57b90228
commit 608e1a6f55
3 changed files with 63 additions and 4 deletions
+59 -3
View File
@@ -447,11 +447,23 @@ impl ClientDiagnostics {
));
}
if self.stats.broadcast_frames_tx() > 0 || self.stats.broadcast_frames_rx() > 0 {
diagnostics.push(UserDiagnostic::new(
match (
self.stats.broadcast_frames_tx() > 0,
self.stats.broadcast_frames_rx() > 0,
) {
(true, true) => diagnostics.push(UserDiagnostic::new(
UserDiagnosticLevel::Info,
"Broadcast traffic flowing",
));
)),
(true, false) => diagnostics.push(UserDiagnostic::new(
UserDiagnosticLevel::Warning,
"Broadcast sent toward LAN; waiting for LAN broadcast reply",
)),
(false, true) => diagnostics.push(UserDiagnostic::new(
UserDiagnosticLevel::Info,
"LAN broadcast received",
)),
(false, false) => {}
}
diagnostics
@@ -723,6 +735,50 @@ mod tests {
assert_eq!(user_diagnostics[2].level(), UserDiagnosticLevel::Warning);
}
#[test]
fn distinguishes_one_way_broadcast_diagnostics() {
let mut diagnostics = ClientDiagnostics::new(
RelayDiagnostics::new(true, true, true),
QuicDiagnostics::new(true, Some(1400)),
TapDiagnostics::new(
true,
Some(MacAddr::new([0x02, 1, 2, 3, 4, 5])),
Some(1200),
None,
),
TunnelStats::default().with_broadcast_frames(1, 0),
);
let broadcast = diagnostics
.user_diagnostics()
.into_iter()
.find(|diagnostic| diagnostic.message().contains("Broadcast"))
.expect("outbound broadcast should produce a diagnostic");
assert_eq!(broadcast.level(), UserDiagnosticLevel::Warning);
assert_eq!(
broadcast.message(),
"Broadcast sent toward LAN; waiting for LAN broadcast reply"
);
diagnostics = ClientDiagnostics::new(
RelayDiagnostics::new(true, true, true),
QuicDiagnostics::new(true, Some(1400)),
TapDiagnostics::new(
true,
Some(MacAddr::new([0x02, 1, 2, 3, 4, 5])),
Some(1200),
None,
),
TunnelStats::default().with_broadcast_frames(0, 1),
);
let broadcast = diagnostics
.user_diagnostics()
.into_iter()
.find(|diagnostic| diagnostic.message().contains("broadcast"))
.expect("inbound broadcast should produce a diagnostic");
assert_eq!(broadcast.level(), UserDiagnosticLevel::Info);
assert_eq!(broadcast.message(), "LAN broadcast received");
}
#[test]
fn reports_link_local_tap_ipv4_as_waiting_for_lan_dhcp() {
let diagnostic = tap_ip_user_diagnostic(Some("169.254.10.20".parse().unwrap())).unwrap();