diff --git a/crates/ecrou/src/krun.rs b/crates/ecrou/src/krun.rs index 395e9bb..db08ff9 100644 --- a/crates/ecrou/src/krun.rs +++ b/crates/ecrou/src/krun.rs @@ -141,6 +141,30 @@ impl Krun { ) } + /// Attach the vsock device with explicit TSI flags. Without this + /// the engine runs TSI in heuristics mode, where guest TLS traffic + /// crawls (~17 KB/s against a CDN); hijacking AF_INET outright + /// puts it on the fast path. Flag bit 0 hijacks AF_INET/AF_INET6, + /// bit 1 AF_UNIX. + pub fn add_vsock(&self, ctx_id: u32, tsi_flags: u32) -> Result<()> { + // The engine materializes an implicit vsock by default; the + // explicit one is only accepted once that is switched off. + let f = symbol!( + self.lib, + b"krun_disable_implicit_vsock\0", + unsafe extern "C" fn(u32) -> i32 + ); + // Safety: plain integer context id. + krun_ret(unsafe { f(ctx_id) }, "krun_disable_implicit_vsock")?; + let f = symbol!( + self.lib, + b"krun_add_vsock\0", + unsafe extern "C" fn(u32, u32) -> i32 + ); + // Safety: plain integers; the engine validates the flag bits. + krun_ret(unsafe { f(ctx_id, tsi_flags) }, "krun_add_vsock") + } + /// `krun_set_workdir` pub fn set_workdir(&self, ctx_id: u32, workdir: &str) -> Result<()> { let workdir_c = CString::new(workdir).context("workdir contains a NUL")?; diff --git a/crates/ecrou/src/vm.rs b/crates/ecrou/src/vm.rs index 8bf9a4b..236e6df 100644 --- a/crates/ecrou/src/vm.rs +++ b/crates/ecrou/src/vm.rs @@ -140,6 +140,9 @@ pub fn run(options: &RunOptions, progress: &dyn Progress) -> Result { for (share, gs) in &share_pairs { krun.add_virtiofs(ctx, &gs.tag, &share.host)?; } + // Explicit vsock with AF_INET hijacked: the implicit heuristics + // mode proxies fine for plain HTTP but starves TLS. + krun.add_vsock(ctx, 0b1)?; // The blob chdirs from KRUN_WORKDIR before exec; the script's cd // stays as the fallback path. if !options.workdir.is_empty() && options.workdir != "/" {