link_up() fails with EHOSTUNREACH on dual-stack devices after link_down()
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 84/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- linux, rust
- Domain
- networking
Research direction
Start at src/iface.rs:379, where Iface::link_up re-adds the IPv4 and IPv6 default routes, and inspect the routed-interface setup alongside the existing IPv6 DAD sysctls. Run the supplied dualstack_link_flap and v4only_link_flap reproductions; done means both link-flap tests pass without the EHOSTUNREACH error.
Written by the indexing model from the issue text.
Description
Summary
Iface::link_up() fails with No route to host (os error 113) on any dual-stack
device. A down/up cycle, which should be a routine fault-injection step, is
therefore impossible on dual-stack topologies, and that includes every device
built from RouterPreset::Home, Corporate, Cloud, IspCgnat or Public.
IpSupport::V4Only devices are unaffected.
Found in patchbay 0.7.0 while porting the iroh-gossip netsim tests from 0.1.
Repro
use patchbay::{IpSupport, Lab, RouterPreset};
#[ctor::ctor(unsafe)]
fn userns_ctor() {
unsafe { patchbay::init_userns_for_ctor(); }
}
// fails: Received a netlink error message No route to host (os error 113)
#[tokio::test]
async fn dualstack_link_flap() -> anyhow::Result<()> {
let lab = Lab::new().await?;
let home = lab.add_router("home").preset(RouterPreset::Home).build().await?;
let dev = lab.add_device("dev").uplink(home.id()).build().await?;
let eth0 = dev.iface("eth0").unwrap();
eth0.link_down().await?;
eth0.link_up().await?;
Ok(())
}
// passes
#[tokio::test]
async fn v4only_link_flap() -> anyhow::Result<()> {
let lab = Lab::new().await?;
let home = lab
.add_router("home")
.preset(RouterPreset::Home)
.ip_support(IpSupport::V4Only)
.build()
.await?;
let dev = lab.add_device("dev").uplink(home.id()).build().await?;
let eth0 = dev.iface("eth0").unwrap();
eth0.link_down().await?;
eth0.link_up().await?;
Ok(())
}
running 2 tests
test dualstack_link_flap ... Error: Received a netlink error message No route to host (os error 113)
FAILED
test v4only_link_flap ... ok
Cause
Linux flushes an interface's IPv6 addresses when the link goes down, unless
net.ipv6.conf.<if>.keep_addr_on_down is set. The kernel default is 0.
Iface::link_up (src/iface.rs:379) re-adds the IPv4 default route and then the
IPv6 one:
nl.replace_default_route_v4(&ifname_route, gw_ip).await?;
nl.set_default_route_v6(&ifname_route, primary_v6).await
By that point eth0 has no IPv6 address, so the gateway
(fd10:0:0:2::1 in the repro) is not on-link and the kernel rejects the route
with EHOSTUNREACH. link_down never emits the corresponding
replace_default_route_* teardown and link_up never re-adds the addresses, so
the two operations are not symmetric for IPv6 the way they are for IPv4.
Relevant trace from the failing run:
patchbay::netlink: set link up ifname=eth0
patchbay::netlink: replace default route v4 ifname=eth0 via=10.0.2.1
patchbay::netlink: replace default route v6 ifname=eth0 via=fd10:0:0:2::1
Error: Received a netlink error message No route to host (os error 113)
Suggested fix
Either of:
- Set
net.ipv6.conf.<if>.keep_addr_on_down=1when creating a routed
interface, alongside the existing DAD sysctls. This matches the
Ipv6DadMode::Disabledphilosophy of making test topologies deterministic,
and the addresses then survive the transition untouched. - Re-add the interface's configured IPv6 addresses in
link_upbefore
installing the v6 default route.
Option 1 is a one-line sysctl and keeps link_up simple.
Workaround
Setting the sysctl from the test before taking the link down is enough:
let path = format!("/proc/sys/net/ipv6/conf/{}/keep_addr_on_down", iface.name());
device.run_sync(move || { std::fs::write(&path, "1")?; Ok(()) })?;
iface.link_down().await?;
Confirmed working: with this in place the dual-stack repro above passes.
Environment
- patchbay 0.7.0 (crates.io)
- Linux 7.1.3-arch2-2, rootless (unprivileged user namespace)
- Dominant language
- Rust
- Stars
- 42
- Forks
- 3
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 1
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from n0-computer/patchbay
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
n0-computer/patchbay#20 ·
-
n0-computer/patchbay#8 · 1 assignee ·
All issues in n0-computer/patchbay
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Eynzof/Hermes-CN-Desktop#610 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
gitbutlerapp/gitbutler#15998 · 1 comment ·
-
bug triage:deciding
Difficulty 1/5 Under an hour Newbie friendliness 88/100
open-telemetry/otel-arrow#4132 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100