Skip to content

Commit

Permalink
refactor(quic): rewrite quic using quinn
Browse files Browse the repository at this point in the history
Rewrite quic using quinn instead of quinn-proto. libp2p-quic::endpoint::Driver is eliminated (and that hard quinn-proto machinery). Also:
- ECN bits are handled
- Support Generic Send Offload (GSO)

Pull-Request: #3454.
  • Loading branch information
kpp authored and thomaseizinger committed Aug 20, 2023
1 parent dea9604 commit ce3efcf
Show file tree
Hide file tree
Showing 17 changed files with 608 additions and 1,803 deletions.
37 changes: 35 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ libp2p-perf = { version = "0.2.0", path = "protocols/perf" }
libp2p-ping = { version = "0.43.0", path = "protocols/ping" }
libp2p-plaintext = { version = "0.40.0", path = "transports/plaintext" }
libp2p-pnet = { version = "0.23.0", path = "transports/pnet" }
libp2p-quic = { version = "0.8.0-alpha", path = "transports/quic" }
libp2p-quic = { version = "0.9.0-alpha", path = "transports/quic" }
libp2p-relay = { version = "0.16.1", path = "protocols/relay" }
libp2p-rendezvous = { version = "0.13.0", path = "protocols/rendezvous" }
libp2p-request-response = { version = "0.25.1", path = "protocols/request-response" }
Expand Down
7 changes: 7 additions & 0 deletions transports/quic/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.9.0-alpha - unreleased

- Use `quinn` instead of `quinn-proto`.
See [PR 3454].

[PR 3454]: https://github.com/libp2p/rust-libp2p/pull/3454

## 0.8.0-alpha

- Raise MSRV to 1.65.
Expand Down
8 changes: 4 additions & 4 deletions transports/quic/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "libp2p-quic"
version = "0.8.0-alpha"
version = "0.9.0-alpha"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
rust-version = { workspace = true }
Expand All @@ -19,15 +19,15 @@ libp2p-tls = { workspace = true }
libp2p-identity = { workspace = true }
log = "0.4"
parking_lot = "0.12.0"
quinn-proto = { version = "0.10.1", default-features = false, features = ["tls-rustls"] }
quinn = { version = "0.10.1", default-features = false, features = ["tls-rustls", "futures-io"] }
rand = "0.8.5"
rustls = { version = "0.21.2", default-features = false }
thiserror = "1.0.44"
tokio = { version = "1.29.1", default-features = false, features = ["net", "rt", "time"], optional = true }

[features]
tokio = ["dep:tokio", "if-watch/tokio"]
async-std = ["dep:async-std", "if-watch/smol"]
tokio = ["dep:tokio", "if-watch/tokio", "quinn/runtime-tokio"]
async-std = ["dep:async-std", "if-watch/smol", "quinn/runtime-async-std"]

# Passing arguments to the docsrs builder in order to properly document cfg's.
# More information: https://docs.rs/about/builds#cross-compiling
Expand Down
142 changes: 142 additions & 0 deletions transports/quic/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use quinn::VarInt;
use std::{sync::Arc, time::Duration};

/// Config for the transport.
#[derive(Clone)]
pub struct Config {
/// Timeout for the initial handshake when establishing a connection.
/// The actual timeout is the minimum of this and the [`Config::max_idle_timeout`].
pub handshake_timeout: Duration,
/// Maximum duration of inactivity in ms to accept before timing out the connection.
pub max_idle_timeout: u32,
/// Period of inactivity before sending a keep-alive packet.
/// Must be set lower than the idle_timeout of both
/// peers to be effective.
///
/// See [`quinn::TransportConfig::keep_alive_interval`] for more
/// info.
pub keep_alive_interval: Duration,
/// Maximum number of incoming bidirectional streams that may be open
/// concurrently by the remote peer.
pub max_concurrent_stream_limit: u32,

/// Max unacknowledged data in bytes that may be send on a single stream.
pub max_stream_data: u32,

/// Max unacknowledged data in bytes that may be send in total on all streams
/// of a connection.
pub max_connection_data: u32,

/// Support QUIC version draft-29 for dialing and listening.
///
/// Per default only QUIC Version 1 / [`libp2p_core::multiaddr::Protocol::QuicV1`]
/// is supported.
///
/// If support for draft-29 is enabled servers support draft-29 and version 1 on all
/// QUIC listening addresses.
/// As client the version is chosen based on the remote's address.
pub support_draft_29: bool,

/// TLS client config for the inner [`quinn::ClientConfig`].
client_tls_config: Arc<rustls::ClientConfig>,
/// TLS server config for the inner [`quinn::ServerConfig`].
server_tls_config: Arc<rustls::ServerConfig>,
}

impl Config {
/// Creates a new configuration object with default values.
pub fn new(keypair: &libp2p_identity::Keypair) -> Self {
let client_tls_config = Arc::new(libp2p_tls::make_client_config(keypair, None).unwrap());
let server_tls_config = Arc::new(libp2p_tls::make_server_config(keypair).unwrap());
Self {
client_tls_config,
server_tls_config,
support_draft_29: false,
handshake_timeout: Duration::from_secs(5),
max_idle_timeout: 30 * 1000,
max_concurrent_stream_limit: 256,
keep_alive_interval: Duration::from_secs(15),
max_connection_data: 15_000_000,

// Ensure that one stream is not consuming the whole connection.
max_stream_data: 10_000_000,
}
}
}

/// Represents the inner configuration for [`quinn`].
#[derive(Debug, Clone)]
pub(crate) struct QuinnConfig {
pub(crate) client_config: quinn::ClientConfig,
pub(crate) server_config: quinn::ServerConfig,
pub(crate) endpoint_config: quinn::EndpointConfig,
}

impl From<Config> for QuinnConfig {
fn from(config: Config) -> QuinnConfig {
let Config {
client_tls_config,
server_tls_config,
max_idle_timeout,
max_concurrent_stream_limit,
keep_alive_interval,
max_connection_data,
max_stream_data,
support_draft_29,
handshake_timeout: _,
} = config;
let mut transport = quinn::TransportConfig::default();
// Disable uni-directional streams.
transport.max_concurrent_uni_streams(0u32.into());
transport.max_concurrent_bidi_streams(max_concurrent_stream_limit.into());
// Disable datagrams.
transport.datagram_receive_buffer_size(None);
transport.keep_alive_interval(Some(keep_alive_interval));
transport.max_idle_timeout(Some(VarInt::from_u32(max_idle_timeout).into()));
transport.allow_spin(false);
transport.stream_receive_window(max_stream_data.into());
transport.receive_window(max_connection_data.into());
let transport = Arc::new(transport);

let mut server_config = quinn::ServerConfig::with_crypto(server_tls_config);
server_config.transport = Arc::clone(&transport);
// Disables connection migration.
// Long-term this should be enabled, however we then need to handle address change
// on connections in the `Connection`.
server_config.migration(false);

let mut client_config = quinn::ClientConfig::new(client_tls_config);
client_config.transport_config(transport);

let mut endpoint_config = quinn::EndpointConfig::default();
if !support_draft_29 {
endpoint_config.supported_versions(vec![1]);
}

QuinnConfig {
client_config,
server_config,
endpoint_config,
}
}
}
Loading

0 comments on commit ce3efcf

Please sign in to comment.