diff options
| author | David Lönnhager <david.l@mullvad.net> | 2023-11-25 16:34:34 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2023-12-04 12:51:30 +0100 |
| commit | 9fa06277f96a5f8f0c319083e58cbb00420c9df6 (patch) | |
| tree | ff10986690237999ae348221863e42846418ca95 /talpid-routing | |
| parent | e119d9bf6fb5445c993db3aac009e08e72c51611 (diff) | |
| download | mullvadvpn-9fa06277f96a5f8f0c319083e58cbb00420c9df6.tar.xz mullvadvpn-9fa06277f96a5f8f0c319083e58cbb00420c9df6.zip | |
Subtract multihop overhead from default route MTU on Linux
Diffstat (limited to 'talpid-routing')
| -rw-r--r-- | talpid-routing/Cargo.toml | 2 | ||||
| -rw-r--r-- | talpid-routing/src/lib.rs | 20 | ||||
| -rw-r--r-- | talpid-routing/src/unix/linux.rs | 20 |
3 files changed, 38 insertions, 4 deletions
diff --git a/talpid-routing/Cargo.toml b/talpid-routing/Cargo.toml index e5cfb9d9f9..31545fe705 100644 --- a/talpid-routing/Cargo.toml +++ b/talpid-routing/Cargo.toml @@ -23,7 +23,7 @@ talpid-types = { path = "../talpid-types" } libc = "0.2" once_cell = { workspace = true } rtnetlink = "0.11" -netlink-packet-route = "0.13" +netlink-packet-route = { version = "0.13", features = ["rich_nlas"] } netlink-sys = "0.8.3" [target.'cfg(target_os = "macos")'.dependencies] diff --git a/talpid-routing/src/lib.rs b/talpid-routing/src/lib.rs index dd5fd3a761..f1bf28d1a2 100644 --- a/talpid-routing/src/lib.rs +++ b/talpid-routing/src/lib.rs @@ -38,6 +38,8 @@ pub struct Route { metric: Option<u32>, #[cfg(target_os = "linux")] table_id: u32, + #[cfg(target_os = "linux")] + mtu: Option<u32>, } impl Route { @@ -49,6 +51,8 @@ impl Route { metric: None, #[cfg(target_os = "linux")] table_id: u32::from(RT_TABLE_MAIN), + #[cfg(target_os = "linux")] + mtu: None, } } @@ -72,6 +76,10 @@ impl fmt::Display for Route { } #[cfg(target_os = "linux")] write!(f, " table {}", self.table_id)?; + #[cfg(target_os = "linux")] + if let Some(mtu) = self.mtu { + write!(f, " mtu {mtu}")?; + } Ok(()) } } @@ -87,6 +95,9 @@ pub struct RequiredRoute { /// Specifies whether the route should be added to the main routing table or not. #[cfg(target_os = "linux")] main_table: bool, + /// Specifies route MTU + #[cfg(target_os = "linux")] + mtu: Option<u16>, } impl RequiredRoute { @@ -97,6 +108,8 @@ impl RequiredRoute { prefix, #[cfg(target_os = "linux")] main_table: true, + #[cfg(target_os = "linux")] + mtu: None, } } @@ -106,6 +119,13 @@ impl RequiredRoute { self.main_table = main_table; self } + + /// Set route MTU to the given value. + #[cfg(target_os = "linux")] + pub fn mtu(mut self, mtu: u16) -> Self { + self.mtu = Some(mtu); + self + } } /// A NetNode represents a network node - either a real one or a symbolic default one. diff --git a/talpid-routing/src/unix/linux.rs b/talpid-routing/src/unix/linux.rs index a2cf19d3b4..600ddd6794 100644 --- a/talpid-routing/src/unix/linux.rs +++ b/talpid-routing/src/unix/linux.rs @@ -20,7 +20,7 @@ use libc::{AF_INET, AF_INET6}; use netlink_packet_route::{ constants::{ARPHRD_LOOPBACK, FIB_RULE_INVERT, FR_ACT_TO_TBL, NLM_F_REQUEST}, link::{nlas::Nla as LinkNla, LinkMessage}, - route::{nlas::Nla as RouteNla, RouteHeader, RouteMessage}, + route::{nlas::Nla as RouteNla, Metrics, RouteHeader, RouteMessage}, rtnl::{ constants::{ RTN_UNSPEC, RTPROT_UNSPEC, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE, RT_TABLE_COMPAT, @@ -293,7 +293,9 @@ impl RouteManagerImpl { } else { self.table_id }; - required_normal_routes.insert(Route::new(node, route.prefix).table(table)); + let mut new_route = Route::new(node, route.prefix).table(table); + new_route.mtu = route.mtu.map(u32::from); + required_normal_routes.insert(new_route); } } } @@ -450,12 +452,13 @@ impl RouteManagerImpl { destination_length, ) .map_err(Error::InvalidNetworkPrefix)?; + let mut node_addr = None; let mut device = None; let mut metric = None; let mut gateway: Option<IpAddr> = None; - let mut table_id = u32::from(msg.header.table); + let mut route_mtu = None; for nla in msg.nlas.iter() { match nla { @@ -501,6 +504,10 @@ impl RouteManagerImpl { RouteNla::Table(id) => { table_id = *id; } + + RouteNla::Metrics(Metrics::Mtu(mtu)) => { + route_mtu = Some(*mtu); + } _ => continue, } } @@ -519,6 +526,7 @@ impl RouteManagerImpl { prefix, metric, table_id, + mtu: route_mtu, })) } @@ -700,6 +708,11 @@ impl RouteManagerImpl { add_message.nlas.push(RouteNla::Priority(metric)); } + // Set route MTU + if let Some(mtu) = route.mtu { + add_message.nlas.push(RouteNla::Metrics(Metrics::Mtu(mtu))); + } + // Need to modify the request in place to set the correct flags to be able to replace any // existing routes - self.handle.route().add_v4().execute() sets the NLM_F_EXCL flag which // will make the request fail if a route with the same destination already exists. @@ -743,6 +756,7 @@ impl RouteManagerImpl { async fn get_mtu_for_route(&self, ip: IpAddr) -> Result<u16> { // RECURSION_LIMIT controls how many times we recurse to find the device name by looking up // an IP with `get_destination_route`. + // TODO: Check route MTU first const RECURSION_LIMIT: usize = 10; const STANDARD_MTU: u16 = 1500; let mut attempted_ip = ip; |
