Skip to content

Commit b755db4

Browse files
Frandomatheus23
andauthored
fix: wait for at least one ipv6 and ipv4 qad report (#3413)
## Description If an endpoint only has a single relay URL configured in its relay map, we currently abort the QAD net reports after a single successful report. However, we also decide whether an endpoint supports IPv6 on the fact if a QAD IPv6 report completed successfully or not. Those are *two* reports though, and if we abort after the first one, we falsely assume that the endpoint has no IPv6 connectivity. This PR changes this in a rather simple way: If we did start both IPv4 and IPv6 reports, we always wait at least until one of each completed. Unrelated to this change, the PR also adds logging when the best address changes. ## Breaking Changes <!-- Optional, if there are any breaking changes document them, including how to migrate older code. --> ## Notes & open questions <!-- Any notes, remarks or open questions you have to make about the PR. --> ## Change checklist <!-- Remove any that are not relevant. --> - [x] Self-review. - [ ] Documentation updates following the [style guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text), if relevant. - [ ] Tests if relevant. - [ ] All breaking changes documented. - [ ] List all breaking changes in the above "Breaking Changes" section. - [ ] Open an issue or PR on any number0 repos that are affected by this breaking change. Give guidance on how the updates should be handled or do the actual updates themselves. The major ones are: - [ ] [`quic-rpc`](https://github.com/n0-computer/quic-rpc) - [ ] [`iroh-gossip`](https://github.com/n0-computer/iroh-gossip) - [ ] [`iroh-blobs`](https://github.com/n0-computer/iroh-blobs) - [ ] [`dumbpipe`](https://github.com/n0-computer/dumbpipe) - [ ] [`sendme`](https://github.com/n0-computer/sendme) --------- Co-authored-by: Philipp Krüger <[email protected]>
1 parent f3e4307 commit b755db4

File tree

2 files changed

+24
-4
lines changed

2 files changed

+24
-4
lines changed

iroh/src/magicsock/node_map/udp_paths.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use std::{collections::BTreeMap, net::SocketAddr};
99

1010
use n0_future::time::Instant;
11+
use tracing::debug;
1112

1213
use super::{IpPort, path_state::PathState};
1314

@@ -24,7 +25,7 @@ use super::{IpPort, path_state::PathState};
2425
///
2526
/// [`MagicSock`]: crate::magicsock::MagicSock
2627
/// [`NodeState`]: super::node_state::NodeState
27-
#[derive(Debug, Default, Clone, Copy)]
28+
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)]
2829
pub(super) enum UdpSendAddr {
2930
/// The UDP address can be relied on to deliver data to the remote node.
3031
///
@@ -117,8 +118,16 @@ impl NodeUdpPaths {
117118
///
118119
/// This should be called any time that `paths` is modified.
119120
pub(super) fn update_to_best_addr(&mut self, now: Instant) {
120-
self.best_ipv4 = self.best_addr(false, now);
121-
self.best = self.best_addr(true, now);
121+
let best_ipv4 = self.best_addr(false, now);
122+
let best = self.best_addr(true, now);
123+
if best_ipv4 != self.best_ipv4 {
124+
debug!(?best_ipv4, "update best addr (IPv4)");
125+
}
126+
if best != self.best {
127+
debug!(?best, "update best addr (IPv4 or IPv6)");
128+
}
129+
self.best_ipv4 = best_ipv4;
130+
self.best = best;
122131
}
123132

124133
/// Returns the current best address of all available paths, ignoring

iroh/src/net_report.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,17 @@ impl Client {
475475

476476
let mut reports = Vec::new();
477477

478+
// We set _pending to true if at least one report was started for each category.
479+
// If we did not start any report for either category, _pending is set to false right away
480+
// (it "completed" in the sense that nothing will ever run). If we did start at least one report,
481+
// _pending is set to true, and will be set to false further down once the first task
482+
// completed.
483+
let mut ipv4_pending = !v4_buf.is_empty();
484+
let mut ipv6_pending = !v6_buf.is_empty();
478485
loop {
479-
if reports.len() >= enough_relays {
486+
// We early-abort the tasks once we have at least `enough_relays` reports,
487+
// and at least one ipv4 and one ipv6 report completed (if they were started, see comment above).
488+
if reports.len() >= enough_relays && !ipv4_pending && !ipv6_pending {
480489
debug!("enough probes: {}", reports.len());
481490
cancel_v4.cancel();
482491
cancel_v6.cancel();
@@ -487,6 +496,7 @@ impl Client {
487496
biased;
488497

489498
val = v4_buf.join_next(), if !v4_buf.is_empty() => {
499+
ipv4_pending = false;
490500
match val {
491501
Some(Ok(Some(Ok(res)))) => {
492502
match res {
@@ -521,6 +531,7 @@ impl Client {
521531
}
522532
}
523533
val = v6_buf.join_next(), if !v6_buf.is_empty() => {
534+
ipv6_pending = false;
524535
match val {
525536
Some(Ok(Some(Ok(res)))) => {
526537
match res {

0 commit comments

Comments
 (0)