ts_netmon (linux): initial netlink dumps run concurrently on one socket → EBUSY, node reports no endpoints

Open Beginner friendly
#485 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
linux, rust

Research direction

The bug is in init_state() in crates/net/underlay/ts_netmon/src/linux/mod.rs, where the link, address and route netlink dumps are merged and sent concurrently on one socket. Read how rtnetlink sends each request on execute(), then change the initial dumps so each starts only after the previous one finishes. Done means the address dump no longer fails with EBUSY and endpoints are published to control.

Written by the indexing model from the issue text.

Description

init_state() in crates/net/underlay/ts_netmon/src/linux/mod.rs merges the link, address and route dumps (.merge(...)). In rtnetlink, execute() sends its request as soon as it is called, so all three requests go out on the same netlink socket at once. The kernel allows only one dump in progress per socket, so the others fail:

netmon error error=Received a netlink error message Resource busy (os error 16)

When the address dump is the one that fails, DirectActor never learns the local addresses. The node then reports no endpoints to control, and peers cannot reach it directly (Addrs: None on peers; only DERP works).

Seen on OpenWrt 25.12 (Linux 6.12, mips32 / QCA9533, MikroTik mAP lite). It may depend on timing on other systems.

Fix (tested): start each dump only after the previous one has finished.

let h_addr = handle.clone();
let h_route = handle.clone();
link_state(handle)
    .chain(futures_util::stream::once(async move { addr_state(h_addr) }).flatten())
    .chain(futures_util::stream::once(async move { route_state(h_route) }).flatten())
    .map_err(io::Error::other)

After this change the error is gone, endpoints are published and direct paths work (verified against a lab Headscale + derper).

AI disclosure: diagnosed and fixed with an AI assistant (Claude) under human direction; tested on real hardware.

Dominant language
Rust
Stars
1.2k
Forks
75
Avg merge
1d 13h
Merged PRs (30d)
22

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from tailscale/tailscale-rs

All issues in tailscale/tailscale-rs

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.