Skip to content

Commit 0583770

Browse files
feat: Define a path migration event (#3598)
* Define a path migration event * Sort order fix Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Signed-off-by: Martin Thomson <mt@lowentropy.net> * Factor event generation Which should save one borrow each time. * Interior mutability * Better factoring of path response * fmt --------- Signed-off-by: Martin Thomson <mt@lowentropy.net> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 6d76b52 commit 0583770

7 files changed

Lines changed: 59 additions & 15 deletions

File tree

neqo-bin/src/server/http09.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,8 @@ impl super::HttpServer for HttpServer {
232232
}
233233
ConnectionEvent::StateChange(_)
234234
| ConnectionEvent::SendStreamCreatable { .. }
235-
| ConnectionEvent::SendStreamComplete { .. } => (),
235+
| ConnectionEvent::SendStreamComplete { .. }
236+
| ConnectionEvent::PathMigrated { .. } => (),
236237
e => qwarn!("unhandled event {e:?}"),
237238
}
238239
}

neqo-http3/src/connection_client.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1170,7 +1170,8 @@ impl Http3Client {
11701170
ConnectionEvent::SendStreamComplete { .. }
11711171
| ConnectionEvent::OutgoingDatagramOutcome { .. }
11721172
| ConnectionEvent::IncomingDatagramDropped
1173-
| ConnectionEvent::SconeUpdated(_) => {}
1173+
| ConnectionEvent::SconeUpdated(_)
1174+
| ConnectionEvent::PathMigrated { .. } => {}
11741175
}
11751176
}
11761177
Ok(())

neqo-http3/src/connection_server.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,8 @@ impl Http3ServerHandler {
377377
| ConnectionEvent::SendStreamCreatable { .. }
378378
| ConnectionEvent::OutgoingDatagramOutcome { .. }
379379
| ConnectionEvent::IncomingDatagramDropped
380-
| ConnectionEvent::SconeUpdated(_) => {}
380+
| ConnectionEvent::SconeUpdated(_)
381+
| ConnectionEvent::PathMigrated { .. } => {}
381382
}
382383
}
383384
Ok(())

neqo-transport/src/connection/mod.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,10 +2096,17 @@ impl Connection {
20962096
.migrate(&path, force, now, &mut self.stats.borrow_mut())
20972097
{
20982098
self.loss_recovery.migrate();
2099+
self.path_migrated(&path);
20992100
}
21002101
Ok(())
21012102
}
21022103

2104+
fn path_migrated(&self, path: &PathRef) {
2105+
let p = path.borrow();
2106+
self.events
2107+
.path_migrated(p.local_address(), p.remote_address());
2108+
}
2109+
21032110
fn migrate_to_preferred_address(&mut self, now: Instant) -> Res<()> {
21042111
let spa: Option<(tparams::PreferredAddress, ConnectionIdEntry<Srt>)> = if matches!(
21052112
self.conn_params.get_preferred_address(),
@@ -2164,8 +2171,12 @@ impl Connection {
21642171
}
21652172

21662173
if self.ensure_permanent(path, now).is_ok() {
2174+
let was_primary = path.borrow().is_primary();
21672175
self.paths
21682176
.handle_migration(path, remote, now, &mut self.stats.borrow_mut());
2177+
if !was_primary {
2178+
self.path_migrated(path);
2179+
}
21692180
} else {
21702181
qinfo!(
21712182
"[{self}] {} Peer migrated, but no connection ID available",
@@ -3376,11 +3387,11 @@ impl Connection {
33763387
}
33773388
Frame::PathResponse { data } => {
33783389
self.stats.borrow_mut().frame_rx.path_response += 1;
3379-
if self
3380-
.paths
3381-
.path_response(data, now, &mut self.stats.borrow_mut())
3390+
if let Some(primary) =
3391+
self.paths
3392+
.path_response(data, now, &mut self.stats.borrow_mut())
33823393
{
3383-
// This PATH_RESPONSE enabled migration; tell loss recovery.
3394+
self.path_migrated(&primary);
33843395
self.loss_recovery.migrate();
33853396
}
33863397
}

neqo-transport/src/connection/tests/migration.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::{
1717
time::{Duration, Instant},
1818
};
1919

20-
use neqo_common::{Datagram, Decoder, qdebug};
20+
use neqo_common::{Datagram, Decoder, event::Provider as _, qdebug};
2121
use test_fixture::{
2222
DEFAULT_ADDR, DEFAULT_ADDR_V4,
2323
assertions::{assert_v4_path, assert_v6_path},
@@ -31,8 +31,9 @@ use super::{
3131
zero_len_cid_client,
3232
};
3333
use crate::{
34-
CloseReason, ConnectionId, ConnectionIdDecoder as _, ConnectionIdGenerator, ConnectionIdRef,
35-
ConnectionParameters, EmptyConnectionIdGenerator, Error, MIN_INITIAL_PACKET_SIZE,
34+
CloseReason, ConnectionEvent, ConnectionId, ConnectionIdDecoder as _, ConnectionIdGenerator,
35+
ConnectionIdRef, ConnectionParameters, EmptyConnectionIdGenerator, Error,
36+
MIN_INITIAL_PACKET_SIZE,
3637
cid::ConnectionIdManager,
3738
connection::tests::{
3839
assert_path_challenge_min_len, connect, send_something_paced, send_with_extra,
@@ -434,6 +435,11 @@ fn migrate_immediate() {
434435
client
435436
.migrate(Some(DEFAULT_ADDR_V4), Some(DEFAULT_ADDR_V4), true, now)
436437
.unwrap();
438+
assert!(client.events().any(|e| matches!(
439+
e,
440+
ConnectionEvent::PathMigrated { local, remote }
441+
if local == DEFAULT_ADDR_V4 && remote == DEFAULT_ADDR_V4
442+
)));
437443

438444
let client1 = send_something(&mut client, now);
439445
assert_v4_path(&client1, true); // Contains PATH_CHALLENGE.
@@ -447,6 +453,11 @@ fn migrate_immediate() {
447453
// The server accepts the first packet and migrates (but probes).
448454
let server1 = server.process(Some(client1), now).dgram().unwrap();
449455
assert_v4_path(&server1, true);
456+
assert!(
457+
server
458+
.events()
459+
.any(|e| matches!(e, ConnectionEvent::PathMigrated { .. }))
460+
);
450461
let server2 = server.process_output(now).dgram().unwrap();
451462
assert_v6_path(&server2, true);
452463

@@ -655,6 +666,11 @@ fn migration(mut client: Connection) {
655666

656667
// Once the client receives the probe response, it migrates to the new path.
657668
client.process_input(resp, now);
669+
assert!(client.events().any(|e| matches!(
670+
e,
671+
ConnectionEvent::PathMigrated { local, remote }
672+
if local == DEFAULT_ADDR_V4 && remote == DEFAULT_ADDR_V4
673+
)));
658674
assert_eq!(client.stats().frame_rx.path_challenge, 1);
659675
let migrate_client = send_something(&mut client, now);
660676
assert_v4_path(&migrate_client, true); // Responds to server probe.

neqo-transport/src/events.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
// Collecting a list of events relevant to whoever is using the Connection.
88

9-
use std::{cell::RefCell, collections::VecDeque, num::NonZeroU64, rc::Rc};
9+
use std::{cell::RefCell, collections::VecDeque, net::SocketAddr, num::NonZeroU64, rc::Rc};
1010

1111
use neqo_common::event::Provider as EventProvider;
1212
use nss::ResumptionToken;
@@ -82,6 +82,11 @@ pub enum ConnectionEvent {
8282
/// An update was received to SCONE throughput advice.
8383
/// The value is the approximate rate in bits per second; None = unknown.
8484
SconeUpdated(Option<NonZeroU64>),
85+
/// A path migration completed; the connection is now sending on this path.
86+
PathMigrated {
87+
local: SocketAddr,
88+
remote: SocketAddr,
89+
},
8590
}
8691

8792
#[derive(Debug, Default, Clone)]
@@ -216,6 +221,10 @@ impl ConnectionEvents {
216221
}
217222
}
218223

224+
pub fn path_migrated(&self, local: SocketAddr, remote: SocketAddr) {
225+
self.insert(ConnectionEvent::PathMigrated { local, remote });
226+
}
227+
219228
fn insert(&self, event: ConnectionEvent) {
220229
let mut q = self.events.borrow_mut();
221230

neqo-transport/src/path.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,15 @@ impl Paths {
322322
}
323323

324324
/// A `PATH_RESPONSE` was received.
325-
/// Returns `true` if migration occurred.
325+
/// Returns `Some` with the new primary path if migration occurred.
326326
/// If PMTUD is enabled and migration occurs, it will be started on the new primary path.
327327
#[must_use]
328-
pub fn path_response(&mut self, response: [u8; 8], now: Instant, stats: &mut Stats) -> bool {
328+
pub fn path_response(
329+
&mut self,
330+
response: [u8; 8],
331+
now: Instant,
332+
stats: &mut Stats,
333+
) -> Option<PathRef> {
329334
// TODO(mt) consider recording an RTT measurement here as we don't train
330335
// RTT for non-primary paths.
331336
for p in &self.paths {
@@ -340,12 +345,12 @@ impl Paths {
340345
if self.pmtud {
341346
primary.borrow_mut().pmtud_mut().start(now, stats);
342347
}
343-
return true;
348+
return Some(primary);
344349
}
345350
break;
346351
}
347352
}
348-
false
353+
None
349354
}
350355

351356
/// Retire all of the connection IDs prior to the indicated sequence number.

0 commit comments

Comments
 (0)