test(tun): wait for IPv6 activation in mobile configuration test

Assert that the configured IPv6 address is registered before forwarding
starts, then wait up to five seconds for the kernel to make it usable.
Netlink acknowledges address creation before asynchronous IPv6
activation completes, so an immediate bind can fail under CI
parallelism.

Disable automatic link-local address generation in the test namespace to
keep startup IPv6 control traffic out of member-routing assertions.

Validation: the original test failed 40 of 320 runs at 32-way
parallelism. The updated test passed all 320 runs; workspace fmt and
clippy also pass.
This commit is contained in:
KKRainbow committed 2026-10-13 11:08:07 +08:00
1 parent ab241c12c9
commit 48c1736006
1 file changed
+25 -3
+25 -3
View File
@@ -1803,10 +1803,12 @@ mod tests {
.status();
}
let net_ns = NetNS::new(Some(namespace.clone()));
// Avoid DAD timing and use an unowned source to test destination claims.
// Avoid DAD probes and use an unowned source to test destination claims.
{
let _guard = net_ns.guard();
std::fs::write("/proc/sys/net/ipv6/conf/default/accept_dad", "0").unwrap();
// Keep automatic link-local traffic out of the member packet streams.
std::fs::write("/proc/sys/net/ipv6/conf/default/addr_gen_mode", "1").unwrap();
let ifcfg = IfConfiger::default();
ifcfg.set_link_status("lo", true).await.unwrap();
ifcfg
@@ -1847,8 +1849,28 @@ mod tests {
);
nic.configure_mobile_tun().await.unwrap();
// Configuration is usable before start_tunnel_forwarding is called.
net_ns.run(|| UdpSocket::bind("[fd00::1]:0")).unwrap();
// Claims are installed before start_tunnel_forwarding is called.
let ifname = nic.tun_ifname().await.unwrap();
assert!(
net_ns
.run(|| IfConfiger::list_addresses(&ifname))
.unwrap()
.contains(&"fd00::1/64".parse().unwrap())
);
// Linux completes IPv6 address activation asynchronously, even without DAD probes.
tokio::time::timeout(Duration::from_secs(5), async {
loop {
match net_ns.run(|| UdpSocket::bind("[fd00::1]:0")) {
Ok(_) => break,
Err(err) if err.kind() == std::io::ErrorKind::AddrNotAvailable => {
tokio::time::sleep(Duration::from_millis(10)).await;
}
Err(err) => panic!("failed to bind the configured IPv6 address: {err}"),
}
}
})
.await
.unwrap();
let route = "2001:db8:1::/64".parse().unwrap();
let public_addr = "2001:db8:2::1/128".parse().unwrap();
for (event, source, destination) in [