Skip to content

Commit 48bdf22

Browse files
committedFeb 6, 2024
Refactor default MTU calculation
1 parent ea8d82e commit 48bdf22

File tree

2 files changed

+43
-47
lines changed

2 files changed

+43
-47
lines changed
 

‎talpid-core/src/tunnel/mod.rs

+35-37
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ use talpid_wireguard;
1717
const OPENVPN_LOG_FILENAME: &str = "openvpn.log";
1818
const WIREGUARD_LOG_FILENAME: &str = "wireguard.log";
1919

20+
/// Set the MTU to the lowest possible whilst still allowing for IPv6 to help with wireless
21+
/// carriers that do a lot of encapsulation.
22+
const DEFAULT_MTU: u16 = if cfg!(target_os = "android") {
23+
1280
24+
} else {
25+
1380
26+
};
27+
2028
/// Results from operations in the tunnel module.
2129
pub type Result<T> = std::result::Result<T, Error>;
2230

@@ -154,13 +162,25 @@ impl TunnelMonitor {
154162
+ Clone
155163
+ 'static,
156164
{
165+
let default_mtu = DEFAULT_MTU;
166+
157167
#[cfg(any(target_os = "linux", target_os = "windows"))]
158-
args.runtime
159-
.block_on(Self::assign_mtu(&args.route_manager, params));
160-
let config = talpid_wireguard::config::Config::from_parameters(params)?;
168+
// Detects the MTU of the device and sets the default tunnel MTU to that minus headers and
169+
// the safety margin
170+
let default_mtu = args
171+
.runtime
172+
.block_on(
173+
args.route_manager
174+
.get_mtu_for_route(params.connection.peer.endpoint.ip()),
175+
)
176+
.map(|mtu| Self::clamp_mtu(params, mtu))
177+
.unwrap_or(default_mtu);
178+
let config = talpid_wireguard::config::Config::from_parameters(params, default_mtu)?;
161179
let monitor = talpid_wireguard::WireguardMonitor::start(
162180
config,
163181
params.options.quantum_resistant,
182+
#[cfg(target_os = "linux")]
183+
detect_mtu,
164184
log.as_deref(),
165185
args,
166186
)?;
@@ -169,58 +189,36 @@ impl TunnelMonitor {
169189
})
170190
}
171191

172-
/// Set the MTU in the tunnel parameters based on the inputted device MTU and some
173-
/// calculations. `peer_mtu` is the detected device MTU.
192+
/// Calculates and appropriate tunnel MTU based on the given peer MTU minus header sizes
174193
#[cfg(any(target_os = "linux", target_os = "windows"))]
175-
fn set_mtu(params: &mut wireguard_types::TunnelParameters, peer_mtu: u16) {
194+
fn clamp_mtu(params: &wireguard_types::TunnelParameters, peer_mtu: u16) -> u16 {
195+
use talpid_tunnel::{
196+
IPV4_HEADER_SIZE, IPV6_HEADER_SIZE, MIN_IPV4_MTU, MIN_IPV6_MTU, WIREGUARD_HEADER_SIZE,
197+
};
176198
// Some users experience fragmentation issues even when we take the interface MTU and
177199
// subtract the header sizes. This is likely due to some program that they use which does
178200
// not change the interface MTU but adds its own header onto the outgoing packets. For this
179201
// reason we subtract some extra bytes from our MTU in order to give other programs some
180202
// safety margin.
181203
const MTU_SAFETY_MARGIN: u16 = 60;
182-
const IPV4_HEADER_SIZE: u16 = 20;
183-
const IPV6_HEADER_SIZE: u16 = 40;
184-
const WIREGUARD_HEADER_SIZE: u16 = 40;
204+
185205
let total_header_size = WIREGUARD_HEADER_SIZE
186206
+ match params.connection.peer.endpoint.is_ipv6() {
187207
false => IPV4_HEADER_SIZE,
188208
true => IPV6_HEADER_SIZE,
189209
};
210+
190211
// The largest peer MTU that we allow
191-
const MAX_PEER_MTU: u16 = 1500 - MTU_SAFETY_MARGIN;
192-
// The minimum allowed MTU size for our tunnel in IPv6 is 1280 and 576 for IPv4
193-
const MIN_IPV4_MTU: u16 = 576;
194-
const MIN_IPV6_MTU: u16 = 1280;
212+
let max_peer_mtu: u16 = 1500 - MTU_SAFETY_MARGIN - total_header_size;
213+
195214
let min_mtu = match params.generic_options.enable_ipv6 {
196215
false => MIN_IPV4_MTU,
197216
true => MIN_IPV6_MTU,
198217
};
199-
let tunnel_mtu = peer_mtu
200-
.saturating_sub(total_header_size)
201-
.clamp(min_mtu, MAX_PEER_MTU - total_header_size);
202-
params.options.mtu = Some(tunnel_mtu);
203-
}
204218

205-
/// Detects the MTU of the device, calculates what the virtual device MTU should be and sets
206-
/// that in the tunnel parameters.
207-
#[cfg(any(target_os = "linux", target_os = "windows"))]
208-
async fn assign_mtu(
209-
route_manager: &RouteManagerHandle,
210-
params: &mut wireguard_types::TunnelParameters,
211-
) {
212-
// Only calculate the mtu automatically if the user has not set any
213-
if params.options.mtu.is_none() {
214-
match route_manager
215-
.get_mtu_for_route(params.connection.peer.endpoint.ip())
216-
.await
217-
{
218-
Ok(mtu) => Self::set_mtu(params, mtu),
219-
Err(e) => {
220-
log::error!("Could not get the MTU for route {}", e);
221-
}
222-
}
223-
}
219+
peer_mtu
220+
.saturating_sub(total_header_size)
221+
.clamp(min_mtu, max_peer_mtu)
224222
}
225223

226224
#[cfg(not(target_os = "android"))]

‎talpid-wireguard/src/config.rs

+8-10
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,6 @@ pub struct Config {
3030
pub obfuscator_config: Option<ObfuscatorConfig>,
3131
}
3232

33-
/// Set the MTU to the lowest possible whilst still allowing for IPv6 to help with wireless
34-
/// carriers that do a lot of encapsulation.
35-
const DEFAULT_MTU: u16 = if cfg!(target_os = "android") {
36-
1280
37-
} else {
38-
1380
39-
};
40-
4133
/// Configuration errors
4234
#[derive(err_derive::Error, Debug)]
4335
pub enum Error {
@@ -52,12 +44,16 @@ pub enum Error {
5244

5345
impl Config {
5446
/// Constructs a Config from parameters
55-
pub fn from_parameters(params: &wireguard::TunnelParameters) -> Result<Config, Error> {
47+
pub fn from_parameters(
48+
params: &wireguard::TunnelParameters,
49+
default_mtu: u16,
50+
) -> Result<Config, Error> {
5651
Self::new(
5752
&params.connection,
5853
&params.options,
5954
&params.generic_options,
6055
&params.obfuscation,
56+
default_mtu,
6157
)
6258
}
6359

@@ -67,9 +63,11 @@ impl Config {
6763
wg_options: &wireguard::TunnelOptions,
6864
generic_options: &GenericTunnelOptions,
6965
obfuscator_config: &Option<ObfuscatorConfig>,
66+
default_mtu: u16,
7067
) -> Result<Config, Error> {
7168
let mut tunnel = connection.tunnel.clone();
72-
let mtu = wg_options.mtu.unwrap_or(DEFAULT_MTU);
69+
70+
let mtu = wg_options.mtu.unwrap_or(default_mtu);
7371

7472
if tunnel.addresses.is_empty() {
7573
return Err(Error::InvalidTunnelIpError);

0 commit comments

Comments
 (0)