Skip to content

Add near-threshold Guard flag stability warnings to help operators troubleshoot Guard flag flapping #198

Description

@cursor

Context

A relay operator posted on the tor-relays mailing list about their relay repeatedly gaining and losing the Guard flag, causing guard/middle probability to fluctuate significantly. The operator could not determine the root cause. The reply from the community suggested checking uptime and reachability — information that could have been surfaced by allium automatically.

Problem

The current relay diagnostics in relay_diagnostics.py only generate Guard eligibility warnings when the relay does not have the Guard flag (if not has_guard:, line 250). This means:

  1. When a relay has the Guard flag but metrics are marginally above thresholds, no warnings are shown
  2. The operator has no indication that their Guard flag is at risk of being lost
  3. When the flag is lost, warnings appear — but by then the operator is already asking "what happened?"
  4. This creates a frustrating cycle where warnings only appear after the damage is done, disappear once the flag is regained, and reappear on the next loss

Operators currently have to manually inspect the per-authority eligibility table and mentally compare values against thresholds to spot near-threshold metrics — exactly the kind of analysis allium should automate.

Proposed Solution

Add near-threshold stability warnings that fire even when the relay currently holds the Guard flag, as info-level notes in the "Notes" section. These would alert operators that their Guard flag is at risk before they lose it.

1. WFU near threshold (highest priority)

When WFU is between 98.0% and 99.0% (configurable margin) and the relay has Guard:

# In relay_diagnostics.py, AFTER the existing `if not has_guard:` block
if has_guard and wfu_eligible and relay_wfu is not None:
    wfu_margin = relay_wfu - GUARD_WFU_DEFAULT  # e.g., 0.005 = 0.5% margin
    if wfu_margin < 0.01:  # Within 1% of threshold
        wfu_pct = relay_wfu * 100
        issues.append({
            'severity': 'info',
            'category': 'guard',
            'title': 'Guard: WFU near threshold',
            'description': f"WFU {wfu_pct:.1f}% is just above the 98% Guard requirement. "
                          "Brief downtime could cause Guard flag loss.",
            'suggestion': 'Your WFU is marginally above the Guard threshold. Even brief '
                         'downtime (restarts, network blips, OOM kills) could drop WFU '
                         'below 98% and cause Guard flag loss. This may explain Guard '
                         'flag fluctuations. To stabilize: 1) Minimize restarts, '
                         '2) Use systemd with Restart=always, 3) Monitor for OOM kills, '
                         '4) Ensure stable network connectivity.',
            'doc_ref': 'https://spec.torproject.org/dir-spec/assigning-flags-vote.html',
        })

2. Bandwidth near threshold

When observed bandwidth is between 2.0 MB/s and 2.5 MB/s and the relay has Guard:

if has_guard and guard_bw_eligible and observed_bandwidth:
    bw_margin = observed_bandwidth - GUARD_BW_GUARANTEE
    if bw_margin < 500_000:  # Within 0.5 MB/s of threshold
        bw_display = f"{observed_bandwidth / 1_000_000:.1f} MB/s"
        issues.append({
            'severity': 'info',
            'category': 'guard',
            'title': 'Guard: bandwidth near threshold',
            'description': f"Observed bandwidth {bw_display} is close to the 2 MB/s "
                          "Guard minimum. Bandwidth fluctuations could cause Guard flag loss.",
            'suggestion': 'Your bandwidth is marginally above the Guard threshold. '
                         'Network congestion or rate limiting could temporarily drop '
                         'it below 2 MB/s and cause Guard flag loss. Check '
                         'RelayBandwidthRate/RelayBandwidthBurst in torrc and ensure '
                         'adequate upstream capacity.',
        })

3. Partial reachability with Guard flag

When relay has Guard but some authorities cannot reach it (existing partial reachability is info, but linking it to Guard risk):

if has_guard and ipv4_count < auth_count and unreachable_ipv4:
    issues.append({
        'severity': 'info',
        'category': 'guard',
        'title': 'Guard: partial reachability may affect stability',
        'description': f"Some authorities ({', '.join(unreachable_ipv4)}) cannot reach "
                      "this relay. If more become unreachable, Guard flag may be lost.",
        'suggestion': 'Intermittent reachability issues can cause flag flapping. '
                     'Verify firewall rules, check for ISP-level issues, and '
                     'monitor network stability.',
    })

Implementation Notes

  • All near-threshold warnings should use 'severity': 'info' so they appear in the blue "Notes" box, not the yellow "Issues" box
  • Near-threshold margins should be defined as constants at the module level for easy tuning
  • Tests should cover: relay with Guard + near-threshold WFU, relay with Guard + near-threshold bandwidth, relay with Guard + partial reachability
  • The if not has_guard: block remains unchanged — these are additive checks

Files to Modify

  • allium/lib/relay_diagnostics.py — Add near-threshold checks after the existing Guard eligibility block
  • tests/ — Add test cases for the new diagnostic scenarios

Impact

This would directly help operators like the one in the mailing list thread understand why their Guard flag is flapping, without needing to post on the mailing list or manually analyze per-authority tables. The information is already available in the consensus data — it just needs to be surfaced proactively.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions