[PR #6180] [management] LegacyLazyFallback — per-peer downgrade for clients without p2p_dynamic capability #27694

Open
opened 2026-08-05 07:09:06 -04:00 by saavagebueno · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/netbirdio/netbird/pull/6180
Author: @MichaelUray
Created: 5/16/2026
Status: 🔄 Open

Base: mainHead: pr/e-legacy-lazy-fallback


📝 Commits (10+)

  • c4844cc proto: add ConnectionMode enum and p2p/relay timeout fields to PeerConfig
  • e0ed831 client: add connectionmode package with Mode type and proto bridge
  • c71c951 client/peer: ResolveModeFromEnv with NB_CONNECTION_MODE and deprecation warns
  • 7d90a5b client: add --connection-mode, --relay-timeout, --p2p-timeout CLI flags
  • cc10c9f client/conn_mgr: replace asymmetric Lazy/ForceRelay precedence with Mode
  • dfd48e9 client/peer: connection mode drives skip-ICE branch in Open()
  • 82877f0 client/engine: forward resolved Mode to per-peer ConnConfig
  • cd0abe8 mgmt/types: add ConnectionMode + p2p/relay timeout to Settings
  • 0022145 openapi: add connection_mode + p2p/relay timeout fields to AccountSettings
  • b22128e mgmt/handlers/accounts: accept connection_mode + timeout settings on PUT

📊 Changes

92 files changed (+10074 additions, -2803 deletions)

View changed files

📝 client/android/client.go (+134 -4)
📝 client/android/peer_notifier.go (+18 -0)
📝 client/android/preferences.go (+85 -0)
📝 client/cmd/root.go (+17 -0)
📝 client/cmd/service.go (+18 -0)
📝 client/cmd/service_installer.go (+57 -0)
📝 client/cmd/testutil_test.go (+2 -1)
📝 client/cmd/up.go (+39 -0)
📝 client/internal/conn_mgr.go (+518 -42)
client/internal/conn_mgr_test.go (+221 -0)
client/internal/conn_state_pusher.go (+332 -0)
client/internal/conn_state_pusher_test.go (+145 -0)
📝 client/internal/connect.go (+19 -0)
client/internal/debouncer/debouncer.go (+53 -0)
📝 client/internal/debug/debug.go (+6 -0)
📝 client/internal/engine.go (+160 -4)
client/internal/engine_pusher_adapters.go (+62 -0)
📝 client/internal/engine_test.go (+1 -1)
📝 client/internal/lazyconn/env.go (+5 -0)
📝 client/internal/lazyconn/inactivity/manager.go (+128 -21)

...and 72 more files

📄 Description

Stacks on top of #6083 ([client, management] Phase 3.7i of #5989: peer-status visibility) — review/merge that one first.

Problem

When an admin sets the account-wide ConnectionMode = p2p-dynamic, clients that pre-date Phase-3.7i don't understand the new enum (they fall back to the legacy LazyConnectionEnabled bool = false). Result: legacy peers eagerly hold ICE forever, wasting battery / metered-link traffic, and never honor the dynamic-inactivity semantics that newer clients respect.

Empirically observed in a mixed fleet: a Phase-3.7i Android client sees ~12 idle P2P tunnels to legacy peers (NetBird 0.51-0.67) immediately on connect, with the legacy peers spamming ~1.3 OFFERs/min indefinitely.

Solution

When the resolved account mode is p2p-dynamic AND a peer does NOT advertise the p2p_dynamic capability (via PeerSystemMeta.SupportedFeatures), the management server downgrades that peer to p2p-lazy with the admin-configured fallback timeout. Applied in two places:

  1. toPeerConfig — the legacy peer's own PeerConfig gets LazyConnectionEnabled=true + extended relay timeout, so it behaves sanely on its own.
  2. appendRemotePeerConfig — the RemotePeerConfig entries that other peers receive about this legacy peer get effective_connection_mode = p2p-lazy too. This is critical for Phase-3.7i clients (e.g. the per-peer-mode-aware guard introduced in #6083) to identify the peer as lazy and suppress eager bootstrap OFFERs toward it.

Settings

Two new account-level fields:

Field Default Range
legacy_lazy_fallback_enabled true bool
legacy_lazy_fallback_timeout_seconds 3600 [60, 86400]

Admins running a fully Phase-3.7i+ fleet can disable the toggle to push raw p2p-dynamic to all peers. Exposed via PUT /api/accounts/{id} and recorded as activity events.

Commits in this PR

  1. proto+client+mgmt: add SupportedFeatures capability advertisement — prerequisite for capability detection.
  2. mgmt/types: add StringPtrEqual + Uint32PtrEqual nil-safe helpers — used by change-detection.
  3. mgmt/types+store: LegacyLazyFallback{Enabled,TimeoutSeconds} — the two new Settings fields.
  4. mgmt/conversion: legacy-client p2p-dynamic -> p2p-lazy fallbacktoPeerConfig downgrade.
  5. mgmt/http+activity: expose LegacyLazyFallback settings via API — PUT endpoint + activity event.
  6. mgmt: legacy-fallback defaults consistent across all construction paths — default propagation through all Settings construction sites.
  7. mgmt/conversion: apply LegacyLazyFallback in appendRemotePeerConfig too — the RemotePeerConfig parity fix (essential for Phase-3.7i-aware clients to suppress eager bootstrap).

Test plan

  • New unit tests in management/internals/shared/grpc/conversion_test.go: TestToPeerConfig_LegacyFallback_* (4 cases for the existing toPeerConfig branch) and TestAppendRemotePeerConfig_LegacyFallback_* (4 cases for the new appendRemotePeerConfig branch). Covers: legacy peer with fallback on, new peer (passes through), fallback toggle off, account in non-p2p-dynamic mode.
  • Production-deployed for ~6 hours on a real mixed fleet (multiple legacy peers running NetBird 0.51-0.67): legacy peers correctly receive LazyConnectionEnabled=true + long relay-timeout in their own PeerConfig, and newer Phase-3.7i clients see them as effective_connection_mode=p2p-lazy in RemotePeerConfig entries.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added connection mode selection (relay-forced, p2p, p2p-lazy, p2p-dynamic) with server and client configuration support.
    • P2P timeout and retry-max configuration for advanced connection behavior tuning.
    • ICE failure backoff state tracking for p2p-dynamic mode resilience.
    • Enhanced peer status reporting with effective/configured connection settings, latency, and bandwidth metrics.
    • Server-pushed connection configuration updates and peer connection state snapshots.
    • Android client configuration getters/setters and enriched peer metadata.
    • Legacy lazy connection fallback support for backward compatibility.
  • Tests

    • Comprehensive test coverage for connection mode resolution and behavior.

Review Change Stack


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/netbirdio/netbird/pull/6180 **Author:** [@MichaelUray](https://github.com/MichaelUray) **Created:** 5/16/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `pr/e-legacy-lazy-fallback` --- ### 📝 Commits (10+) - [`c4844cc`](https://github.com/netbirdio/netbird/commit/c4844ccfd1361ad48194731423a7f873a73a24f7) proto: add ConnectionMode enum and p2p/relay timeout fields to PeerConfig - [`e0ed831`](https://github.com/netbirdio/netbird/commit/e0ed8313697835bafa34556aec487bc782e95307) client: add connectionmode package with Mode type and proto bridge - [`c71c951`](https://github.com/netbirdio/netbird/commit/c71c951d88b9ce5fb2d224684e50e6dd31d77072) client/peer: ResolveModeFromEnv with NB_CONNECTION_MODE and deprecation warns - [`7d90a5b`](https://github.com/netbirdio/netbird/commit/7d90a5bdd5cc598293640d1c8bcfa23ee866e6c6) client: add --connection-mode, --relay-timeout, --p2p-timeout CLI flags - [`cc10c9f`](https://github.com/netbirdio/netbird/commit/cc10c9f108fce4b90edf7d4f4bf399e53057e038) client/conn_mgr: replace asymmetric Lazy/ForceRelay precedence with Mode - [`dfd48e9`](https://github.com/netbirdio/netbird/commit/dfd48e920bf889a20ef699b5aaff1a0a4b64d491) client/peer: connection mode drives skip-ICE branch in Open() - [`82877f0`](https://github.com/netbirdio/netbird/commit/82877f0ce8cb23ba722f393d47b50a508dc692bd) client/engine: forward resolved Mode to per-peer ConnConfig - [`cd0abe8`](https://github.com/netbirdio/netbird/commit/cd0abe890d579c0dfbbb2251b4451d62c5b9e3bf) mgmt/types: add ConnectionMode + p2p/relay timeout to Settings - [`0022145`](https://github.com/netbirdio/netbird/commit/0022145a414e794f7701250460b10badba7741b5) openapi: add connection_mode + p2p/relay timeout fields to AccountSettings - [`b22128e`](https://github.com/netbirdio/netbird/commit/b22128ed14f35d56d75e640f986d2e934414401d) mgmt/handlers/accounts: accept connection_mode + timeout settings on PUT ### 📊 Changes **92 files changed** (+10074 additions, -2803 deletions) <details> <summary>View changed files</summary> 📝 `client/android/client.go` (+134 -4) 📝 `client/android/peer_notifier.go` (+18 -0) 📝 `client/android/preferences.go` (+85 -0) 📝 `client/cmd/root.go` (+17 -0) 📝 `client/cmd/service.go` (+18 -0) 📝 `client/cmd/service_installer.go` (+57 -0) 📝 `client/cmd/testutil_test.go` (+2 -1) 📝 `client/cmd/up.go` (+39 -0) 📝 `client/internal/conn_mgr.go` (+518 -42) ➕ `client/internal/conn_mgr_test.go` (+221 -0) ➕ `client/internal/conn_state_pusher.go` (+332 -0) ➕ `client/internal/conn_state_pusher_test.go` (+145 -0) 📝 `client/internal/connect.go` (+19 -0) ➕ `client/internal/debouncer/debouncer.go` (+53 -0) 📝 `client/internal/debug/debug.go` (+6 -0) 📝 `client/internal/engine.go` (+160 -4) ➕ `client/internal/engine_pusher_adapters.go` (+62 -0) 📝 `client/internal/engine_test.go` (+1 -1) 📝 `client/internal/lazyconn/env.go` (+5 -0) 📝 `client/internal/lazyconn/inactivity/manager.go` (+128 -21) _...and 72 more files_ </details> ### 📄 Description **Stacks on top of #6083** ([client, management] Phase 3.7i of #5989: peer-status visibility) — review/merge that one first. ## Problem When an admin sets the account-wide `ConnectionMode = p2p-dynamic`, clients that pre-date Phase-3.7i don't understand the new enum (they fall back to the legacy `LazyConnectionEnabled` bool = false). Result: legacy peers eagerly hold ICE forever, wasting battery / metered-link traffic, and never honor the dynamic-inactivity semantics that newer clients respect. Empirically observed in a mixed fleet: a Phase-3.7i Android client sees ~12 idle P2P tunnels to legacy peers (NetBird 0.51-0.67) immediately on connect, with the legacy peers spamming ~1.3 OFFERs/min indefinitely. ## Solution When the resolved account mode is `p2p-dynamic` AND a peer does NOT advertise the `p2p_dynamic` capability (via `PeerSystemMeta.SupportedFeatures`), the management server downgrades that peer to `p2p-lazy` with the admin-configured fallback timeout. Applied in two places: 1. **`toPeerConfig`** — the legacy peer's own `PeerConfig` gets `LazyConnectionEnabled=true` + extended relay timeout, so it behaves sanely on its own. 2. **`appendRemotePeerConfig`** — the `RemotePeerConfig` entries that *other* peers receive about this legacy peer get `effective_connection_mode = p2p-lazy` too. This is critical for Phase-3.7i clients (e.g. the per-peer-mode-aware guard introduced in #6083) to identify the peer as lazy and suppress eager bootstrap OFFERs toward it. ## Settings Two new account-level fields: | Field | Default | Range | |---|---|---| | `legacy_lazy_fallback_enabled` | `true` | bool | | `legacy_lazy_fallback_timeout_seconds` | `3600` | [60, 86400] | Admins running a fully Phase-3.7i+ fleet can disable the toggle to push raw p2p-dynamic to all peers. Exposed via PUT `/api/accounts/{id}` and recorded as activity events. ## Commits in this PR 1. `proto+client+mgmt: add SupportedFeatures capability advertisement` — prerequisite for capability detection. 2. `mgmt/types: add StringPtrEqual + Uint32PtrEqual nil-safe helpers` — used by change-detection. 3. `mgmt/types+store: LegacyLazyFallback{Enabled,TimeoutSeconds}` — the two new Settings fields. 4. `mgmt/conversion: legacy-client p2p-dynamic -> p2p-lazy fallback` — `toPeerConfig` downgrade. 5. `mgmt/http+activity: expose LegacyLazyFallback settings via API` — PUT endpoint + activity event. 6. `mgmt: legacy-fallback defaults consistent across all construction paths` — default propagation through all Settings construction sites. 7. `mgmt/conversion: apply LegacyLazyFallback in appendRemotePeerConfig too` — the RemotePeerConfig parity fix (essential for Phase-3.7i-aware clients to suppress eager bootstrap). ## Test plan - New unit tests in `management/internals/shared/grpc/conversion_test.go`: `TestToPeerConfig_LegacyFallback_*` (4 cases for the existing toPeerConfig branch) and `TestAppendRemotePeerConfig_LegacyFallback_*` (4 cases for the new appendRemotePeerConfig branch). Covers: legacy peer with fallback on, new peer (passes through), fallback toggle off, account in non-p2p-dynamic mode. - Production-deployed for ~6 hours on a real mixed fleet (multiple legacy peers running NetBird 0.51-0.67): legacy peers correctly receive `LazyConnectionEnabled=true` + long relay-timeout in their own PeerConfig, and newer Phase-3.7i clients see them as `effective_connection_mode=p2p-lazy` in RemotePeerConfig entries. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit # Release Notes * **New Features** * Added connection mode selection (relay-forced, p2p, p2p-lazy, p2p-dynamic) with server and client configuration support. * P2P timeout and retry-max configuration for advanced connection behavior tuning. * ICE failure backoff state tracking for p2p-dynamic mode resilience. * Enhanced peer status reporting with effective/configured connection settings, latency, and bandwidth metrics. * Server-pushed connection configuration updates and peer connection state snapshots. * Android client configuration getters/setters and enriched peer metadata. * Legacy lazy connection fallback support for backward compatibility. * **Tests** * Comprehensive test coverage for connection mode resolution and behavior. <!-- review_stack_entry_start --> [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/netbirdio/netbird/pull/6180?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
saavagebueno added the pull-request label 2026-08-05 07:09:06 -04:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#27694