summaryrefslogtreecommitdiffhomepage
path: root/talpid-routing
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2023-11-25 16:34:34 +0100
committerDavid Lönnhager <david.l@mullvad.net>2023-12-04 12:51:30 +0100
commit9fa06277f96a5f8f0c319083e58cbb00420c9df6 (patch)
treeff10986690237999ae348221863e42846418ca95 /talpid-routing
parente119d9bf6fb5445c993db3aac009e08e72c51611 (diff)
downloadmullvadvpn-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.toml2
-rw-r--r--talpid-routing/src/lib.rs20
-rw-r--r--talpid-routing/src/unix/linux.rs20
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;