[GH-ISSUE #6250] [client] Lazy-suspend wipes route-manager AllowedIPs; routed-subnet traffic blackholes until manual route resync #12935

Closed
opened 2026-08-05 02:07:02 -04:00 by saavagebueno · 2 comments
Owner

Originally created by @vpsie on GitHub (May 22, 2026).
Original GitHub issue: https://github.com/netbirdio/netbird/issues/6250

Describe the problem

In lazy-connection mode (default on most self-hosted deployments), a peer that is also a routing peer can become unreachable for traffic to its advertised subnets while the peer itself still shows as Connected in netbird status -d. The fault reproduces on current main and on the 0.71.4 release.

The mechanism is internal to the client:

  1. peer.Conn.Close in client/internal/peer/conn.go calls endpointUpdater.RemoveWgPeer unconditionally. That removes the entire WG peer entry on the WireGuard interface.
  2. The lazy-manager invokes Conn.Close on the lazy-suspend path (peerstore.PeerConnIdle / peerstore.PeerConnClose) the same way it does on permanent removal.
  3. The route-manager extends a routing peer's AllowedIPs in place via WgInterface.AddAllowedIP through its allowedIPsRefCounter. RemoveWgPeer wipes those alongside the rest.
  4. The next lazy-wake re-opens the connection using only the original PeerConfig.AllowedIps (the peer's base /32). The refcounter never re-applies the routed prefixes until a full management-side reconcile fires.

Visible symptom in netbird status -d:

Status: Connected
Connection type: P2P
Last WireGuard handshake: <recent>
Networks: -
Transfer status (received/sent) <bytes>/<bytes>

Traffic to the peer's advertised subnets is dropped by WG (no matching peer for the destination). Toggling the affected network off and back on in the GUI Networks panel forces a full route resync that re-applies the prefix and restores connectivity.

To Reproduce

  1. Self-hosted NetBird control plane with lazy connection enabled (LazyConnectionEnabled=true on the management side, the current default).
  2. At least one routing peer that advertises a subnet.
  3. From any other peer, allow the lazy-manager to suspend the routing peer (idle timeout), then attempt traffic to its advertised subnet.
  4. Observe 100% packet loss; the peer status shows Connected but Networks: -.

Expected behavior

Route-manager-applied AllowedIPs survive a lazy wake/sleep cycle so routed-subnet traffic flows on the first packet without operator intervention.

Workaround

Uncheck and re-check the network in the GUI Networks panel. The resulting route resync re-applies the prefix and traffic flows again.

Are you using NetBird Cloud?

Self-hosted.

NetBird version

Reproduces on main (HEAD at time of report) and on the 0.71.4 release.

Related

  • #4769 — multiple reporters of the same observable symptom on routing peers requiring netbird down && netbird up on the router peer.
  • PR #6084 — broader p2p-dynamic rework; the same code path is addressed as part of a keepWgPeer commit inside that 4-PR stack.

Proposed fix

PR follows: gate the RemoveWgPeer call in Conn.Close on a new keepWgPeer bool parameter. Lazy-suspend callers pass true; the permanent-removal caller passes false. This is the minimum change against main so the fix can land ahead of the full #6084 stack.

Originally created by @vpsie on GitHub (May 22, 2026). Original GitHub issue: https://github.com/netbirdio/netbird/issues/6250 **Describe the problem** In lazy-connection mode (default on most self-hosted deployments), a peer that is also a routing peer can become unreachable for traffic to its advertised subnets while the peer itself still shows as `Connected` in `netbird status -d`. The fault reproduces on current `main` and on the 0.71.4 release. The mechanism is internal to the client: 1. `peer.Conn.Close` in `client/internal/peer/conn.go` calls `endpointUpdater.RemoveWgPeer` unconditionally. That removes the entire WG peer entry on the WireGuard interface. 2. The lazy-manager invokes `Conn.Close` on the lazy-suspend path (`peerstore.PeerConnIdle` / `peerstore.PeerConnClose`) the same way it does on permanent removal. 3. The route-manager extends a routing peer's AllowedIPs in place via `WgInterface.AddAllowedIP` through its `allowedIPsRefCounter`. `RemoveWgPeer` wipes those alongside the rest. 4. The next lazy-wake re-opens the connection using only the original `PeerConfig.AllowedIps` (the peer's base /32). The refcounter never re-applies the routed prefixes until a full management-side reconcile fires. Visible symptom in `netbird status -d`: ``` Status: Connected Connection type: P2P Last WireGuard handshake: <recent> Networks: - Transfer status (received/sent) <bytes>/<bytes> ``` Traffic to the peer's advertised subnets is dropped by WG (no matching peer for the destination). Toggling the affected network off and back on in the GUI Networks panel forces a full route resync that re-applies the prefix and restores connectivity. **To Reproduce** 1. Self-hosted NetBird control plane with lazy connection enabled (`LazyConnectionEnabled=true` on the management side, the current default). 2. At least one routing peer that advertises a subnet. 3. From any other peer, allow the lazy-manager to suspend the routing peer (idle timeout), then attempt traffic to its advertised subnet. 4. Observe 100% packet loss; the peer status shows `Connected` but `Networks: -`. **Expected behavior** Route-manager-applied AllowedIPs survive a lazy wake/sleep cycle so routed-subnet traffic flows on the first packet without operator intervention. **Workaround** Uncheck and re-check the network in the GUI Networks panel. The resulting route resync re-applies the prefix and traffic flows again. **Are you using NetBird Cloud?** Self-hosted. **NetBird version** Reproduces on `main` (HEAD at time of report) and on the 0.71.4 release. **Related** - #4769 — multiple reporters of the same observable symptom on routing peers requiring `netbird down && netbird up` on the router peer. - PR #6084 — broader p2p-dynamic rework; the same code path is addressed as part of a `keepWgPeer` commit inside that 4-PR stack. **Proposed fix** PR follows: gate the `RemoveWgPeer` call in `Conn.Close` on a new `keepWgPeer bool` parameter. Lazy-suspend callers pass `true`; the permanent-removal caller passes `false`. This is the minimum change against `main` so the fix can land ahead of the full #6084 stack.
Author
Owner

@linear-code[bot] commented on GitHub (May 22, 2026):

NET-1203

<!-- gh-comment-id:4521257054 --> @linear-code[bot] commented on GitHub (May 22, 2026): <!-- linear-linkback --> <p><a href="https://linear.app/netbird/issue/NET-1203">NET-1203</a></p>
Author
Owner

@jnfrati commented on GitHub (May 27, 2026):

@vpsie this issue circumvented the issue triage flow (see more here)

Although we appreciate new people willing to contribute into the platform, we also encourage a small back and forth with the team before opening a PR, specially when we're talking about modifying behavior on the client side due to it's high impact.

I'm going to move this to a discussion, if we can replicate the issue we'll re-open and take a look at the PR, otherwise it will be closed.

<!-- gh-comment-id:4559389633 --> @jnfrati commented on GitHub (May 27, 2026): @vpsie this issue circumvented the issue triage flow ([see more here](https://github.com/netbirdio/netbird/discussions/6075)) Although we appreciate new people willing to contribute into the platform, we also encourage a small back and forth with the team before opening a PR, specially when we're talking about modifying behavior on the client side due to it's high impact. I'm going to move this to a discussion, if we can replicate the issue we'll re-open and take a look at the PR, otherwise it will be closed.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DYNR/netbird#12935