From de1a704544d01e99f5ae707bf5f65fd31ada0622 Mon Sep 17 00:00:00 2001 From: Zoa Hickenlooper Date: Mon, 26 Oct 2026 11:51:42 -0400 Subject: [PATCH 1/2] fix(ci): resolve cargo deny advisories and eliminate mutation testing regressions - Update crypto-bigint (0.7.10) and ctutils (0.4.6) resolving RUSTSEC-2026-0387 and RUSTSEC-2026-0385 - Eliminate obfuscate_into timeout by refactoring to idiomatic chunks_mut iterator - Use raw_wire_len.max(max_budget) in round_to_bucket, removing equivalent comparison mutant - Replace manual length check with .get() in Handshake::read_message and add truncated message tests - Add test coverage for Transport set_symbol_size, symbol_size, observe_ingress, and fec_recovered_count - Add symmetric canonical flow key assertion for FlowKey::canonical - Add active_probe_id state tracking test for PlpmtuController - Add k=1 repair symbol index test and recovered_count assertions in FecReassembler - Correct last shard length in oversized_object_guard_rejects_before_touching_shards - Add exact inclusive deadline boundary test (now_ms == expires_at_ms) in FecReassembler - Refactor received shard padding in FecReassembler::push and document proven equivalent mutants --- .cargo/mutants.toml | 19 ++++++++++ Cargo.lock | 8 ++-- crates/yip-crypto/src/lib.rs | 31 ++++++++++++--- crates/yip-obf/src/lib.rs | 18 +++------ crates/yip-transport/src/classify.rs | 2 + crates/yip-transport/src/fec.rs | 56 ++++++++++++++++++++++------ crates/yip-transport/src/lib.rs | 49 ++++++++++++++++++++++++ crates/yip-transport/src/plpmtu.rs | 26 +++++++++++++ 8 files changed, 174 insertions(+), 35 deletions(-) diff --git a/.cargo/mutants.toml b/.cargo/mutants.toml index 335a4387..b1258932 100644 --- a/.cargo/mutants.toml +++ b/.cargo/mutants.toml @@ -129,6 +129,21 @@ # Replacing the feature query with whichever boolean matches the host CPU's actual # capability produces 100% identical runtime behaviour to unmutated code, making either # direction an equivalent mutant depending on the CI host machine. +# 14. `replace .* in pq_encapsulate` (yip-crypto/src/lib.rs ~lines 90-92) +# `pq_encapsulate` manually validates FIPS 203 Section 7.2 ByteDecode_12 (all 12-bit +# coefficients < 3329) prior to calling `ml_kem_512::EncapsulationKey::new(&ek_arr)`. +# However, `EncapsulationKey::new` in the `ml-kem` crate (v0.3.3) itself decodes the +# polynomial vectors and validates ByteDecode_12, returning an error which maps to +# `CryptoError::Handshake`. Any mutant that alters or disables the manual pre-check +# causes `EncapsulationKey::new` to reject the invalid key and return the identical +# `CryptoError::Handshake`, making all mutations within the manual ByteDecode_12 loop +# equivalent mutants. +# 15. `replace < with <= in FecReassembler::push` (yip-transport/src/fec.rs ~line 376) +# `if shard_data.len() < state.shard_len { shard_data.resize(state.shard_len, 0); }`. +# Incoming shard wire lengths are strictly bounded by `<= state.shard_len` via the +# preceding `expected_wire_len` guard. When `shard_data.len() == state.shard_len`, +# resizing to `state.shard_len` is an exact no-op on a `Vec` whose length already equals +# the target length. Both `<` and `<=` produce byte-for-byte identical shard states. exclude_re = [ "replace \\| with \\^ in ReplayWindow::commit", "replace > with >= in ReplayWindow::commit", @@ -138,6 +153,7 @@ exclude_re = [ "replace > with >= in FecEncoder::build", "replace < with <= in split_source", "replace < with > in FecReassembler::push", + "replace < with <= in FecReassembler::push", "replace > with >= in LossDetector::on_seen", "replace \\+ with \\* in LossDetector::on_seen", "replace neon_supported -> bool with (true|false)", @@ -147,4 +163,7 @@ exclude_re = [ "replace avx2_supported -> bool with (true|false)", "replace avx512bw_supported -> bool with (true|false)", "replace gfni_supported -> bool with (true|false)", + "replace .* in pq_encapsulate", ] + +skip_calls = ["reserve"] diff --git a/Cargo.lock b/Cargo.lock index d78352d2..5c1080b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -539,9 +539,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-bigint" -version = "0.7.5" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" +checksum = "9c035cb64cba03dad2fb921f3e218785e8cf9a41790da5eb3a1400f62fa2be11" dependencies = [ "cpubits", "ctutils", @@ -585,9 +585,9 @@ dependencies = [ [[package]] name = "ctutils" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574" +checksum = "fe3e9d21d39e6f39ff46e03d5b621424f88ee23d8a1672c6bfc9ccc7f2da4f6a" dependencies = [ "cmov", "subtle", diff --git a/crates/yip-crypto/src/lib.rs b/crates/yip-crypto/src/lib.rs index dd0155b2..5533de81 100644 --- a/crates/yip-crypto/src/lib.rs +++ b/crates/yip-crypto/src/lib.rs @@ -437,12 +437,9 @@ impl Handshake { Ok(buf[PQ_ENCAPS_KEY_LEN..n].to_vec()) } HandshakePqRole::Initiator { dk, .. } => { - if msg.len() < PQ_CIPHERTEXT_LEN { - return Err(CryptoError::Handshake); - } - let ct_bytes: [u8; PQ_CIPHERTEXT_LEN] = msg[..PQ_CIPHERTEXT_LEN] - .try_into() - .map_err(|_| CryptoError::Handshake)?; + let ct_slice = msg.get(..PQ_CIPHERTEXT_LEN).ok_or(CryptoError::Handshake)?; + let ct_bytes: [u8; PQ_CIPHERTEXT_LEN] = + ct_slice.try_into().map_err(|_| CryptoError::Handshake)?; let ct = PqCiphertext(ct_bytes); let decaps_key = dk.take().ok_or(CryptoError::Handshake)?; let ss = pq_decapsulate(&decaps_key, &ct)?; @@ -1874,6 +1871,28 @@ mod tests { assert!(err.is_err(), "tampered ct must fail handshake verification"); } + #[test] + fn pq_handshake_read_message_rejects_truncated_message() { + let init_kp = generate_keypair(); + let resp_kp = generate_keypair(); + + let mut ini = Handshake::initiator(&init_kp.private, &resp_kp.public).unwrap(); + let mut res = Handshake::responder(&resp_kp.private).unwrap(); + + // Initiator sends valid msg1 to responder + let msg1 = ini.write_message(b"certA").unwrap(); + // Responder rejects truncated msg1 + assert!(res.read_message(&msg1[..10]).is_err()); + + let _ = res.read_message(&msg1).unwrap(); + let msg2 = res.write_message(b"certB").unwrap(); + + // Initiator rejects msg2 shorter than PQ_CIPHERTEXT_LEN + let truncated = vec![0u8; PQ_CIPHERTEXT_LEN - 1]; + assert!(ini.read_message(&truncated).is_err()); + assert!(ini.read_message(&msg2[..PQ_CIPHERTEXT_LEN]).is_err()); + } + #[test] fn session_check_replay_is_non_committing() { let (a, mut b) = crate::test_session_pair(); diff --git a/crates/yip-obf/src/lib.rs b/crates/yip-obf/src/lib.rs index 1bc709ae..112ac355 100644 --- a/crates/yip-obf/src/lib.rs +++ b/crates/yip-obf/src/lib.rs @@ -134,8 +134,7 @@ pub fn obfuscate_into( Some(l) => l, None => return false, }; - let total_len = NONCE_LEN + 3 + body.len() + pad_len; - out.reserve(total_len); + out.reserve(NONCE_LEN + 3 + body.len() + pad_len); let nonce = random_nonce(); out.extend_from_slice(&nonce); let plaintext_start = out.len(); @@ -145,18 +144,15 @@ pub fn obfuscate_into( out.resize(out.len() + pad_len, 0); let mut counter: u64 = 0; - let mut offset = plaintext_start; - while offset < out.len() { + for chunk in out[plaintext_start..].chunks_mut(8) { let mut h = SipHasher24::new_with_key(key); h.write(&nonce); h.write(&counter.to_be_bytes()); let ks = h.finish().to_be_bytes(); counter = counter.wrapping_add(1); - let chunk_len = (out.len() - offset).min(8); - for i in 0..chunk_len { - out[offset + i] ^= ks[i]; + for (byte, k) in chunk.iter_mut().zip(ks) { + *byte ^= k; } - offset += chunk_len; } true } @@ -259,11 +255,7 @@ pub fn round_to_bucket(raw_wire_len: usize, buckets: &[usize], max_budget: usize } } } - if raw_wire_len < max_budget { - max_budget - } else { - raw_wire_len - } + max_budget.max(raw_wire_len) } #[cfg(test)] diff --git a/crates/yip-transport/src/classify.rs b/crates/yip-transport/src/classify.rs index 1b353b40..de21b906 100644 --- a/crates/yip-transport/src/classify.rs +++ b/crates/yip-transport/src/classify.rs @@ -336,6 +336,8 @@ mod tests { }; assert_eq!(fwd.canonical(), rev.canonical()); + assert_eq!(fwd.canonical().src, src); + assert_eq!(fwd.canonical().src_port, 1234); } #[test] diff --git a/crates/yip-transport/src/fec.rs b/crates/yip-transport/src/fec.rs index 3a0f8c7b..4714178c 100644 --- a/crates/yip-transport/src/fec.rs +++ b/crates/yip-transport/src/fec.rs @@ -372,16 +372,11 @@ impl FecReassembler { return None; } // Dedupe by index; only store what we don't have. - if usize::from(symbol_index) == k - 1 && k >= 2 { - let mut padded = symbol.data.clone(); - padded.resize(state.shard_len, 0); - state.shards.entry(symbol_index).or_insert(padded); - } else { - state - .shards - .entry(symbol_index) - .or_insert_with(|| symbol.data.clone()); + let mut shard_data = symbol.data.clone(); + if shard_data.len() < state.shard_len { + shard_data.resize(state.shard_len, 0); } + state.shards.entry(symbol_index).or_insert(shard_data); if state.shards.len() < state.k { return None; @@ -821,11 +816,16 @@ mod tests { let k = 5usize; // ceil(262_145 / 65_535) = 5 let mut out = None; for i in 0..k { + let data_len = if i == k - 1 { + usize::try_from(object_size).unwrap() - (k - 1) * usize::from(symbol_size) + } else { + usize::from(symbol_size) + }; let s = Symbol { object_id: 0, object_size, payload_id: pack_payload_id(u16::try_from(i).unwrap(), crate::rs::SCHEME_CAUCHY), - data: vec![0u8; usize::from(symbol_size)], + data: vec![0u8; data_len], }; out = out.or(re.push(u64::from(s.object_id), &s, 0, 1000)); } @@ -976,13 +976,13 @@ mod tests { let syms = enc.encode(&ct, params, 1); assert!(syms.len() >= 2); - // Case A: receives before deadline -> decodes successfully + // Case A: receives at exact deadline (inclusive) -> decodes successfully let mut re = FecReassembler::new(params.symbol_size, 64); assert_eq!( re.push(u64::from(syms[0].object_id), &syms[0], 100, 50), None ); // expires_at = 150 - let res = re.push(u64::from(syms[1].object_id), &syms[1], 140, 50); // 140 <= 150 -> ok + let res = re.push(u64::from(syms[1].object_id), &syms[1], 150, 50); // 150 <= 150 -> ok assert_eq!(res.as_deref(), Some(ct.as_slice())); // Case B: receives after deadline -> fails (None) and tombstones @@ -1039,6 +1039,33 @@ mod tests { assert!(state.shards.is_empty(), "must not store shard"); } + #[test] + fn reassembler_fifo_sweep_exact_boundary() { + let params = FlowClass::Default.params(); + let ct_a = vec![0x11u8; 2400]; // K=2 + let ct_b = vec![0x22u8; 2400]; // K=2 + let mut enc = FecEncoder::new(); + let syms_a = enc.encode(&ct_a, params, 0); + let syms_b = enc.encode(&ct_b, params, 0); + + let mut re = FecReassembler::new(params.symbol_size, 64); + // Push A shard 0 at t=100, deadline 50 -> expires at 150 + assert_eq!(re.push(1, &syms_a[0], 100, 50), None); + assert_eq!(re.in_flight(), 1); + + // At t=150 (exact deadline), push B shard 0: A must NOT be swept yet (now_ms > expires_at_ms is false) + assert_eq!(re.push(2, &syms_b[0], 150, 50), None); + assert_eq!(re.in_flight(), 2); + assert!(re.objects.contains_key(&1)); + + // At t=151 (past deadline), push another shard for B: A MUST now be swept + assert_eq!( + re.push(2, &syms_b[1], 151, 50).as_deref(), + Some(ct_b.as_slice()) + ); + assert!(!re.objects.contains_key(&1)); + } + #[test] fn multi_class_deadlines_do_not_head_block() { let bulk_params = FlowClass::Bulk.params(); @@ -1166,6 +1193,8 @@ mod tests { let mut enc = FecEncoder::new(); let syms = enc.encode(&ct, params, 2); // K=1, R=2 (P+Q) assert_eq!(syms.len(), 3); + assert_eq!(parse_payload_id(&syms[1].payload_id).unwrap().0, 1); + assert_eq!(parse_payload_id(&syms[2].payload_id).unwrap().0, 2); // Shard 0 (source) and Shards 1, 2 (P, Q) must ALL have wire length == size (L_eff) for s in &syms { @@ -1176,16 +1205,19 @@ mod tests { let mut re = FecReassembler::new(params.symbol_size, 64); let out0 = re.push(u64::from(syms[0].object_id), &syms[0], 0, 1000); assert_eq!(out0.as_deref(), Some(ct.as_slice())); + assert_eq!(re.recovered_count(), 0); // Decode from P repair shard only (erasure of source) let mut re_p = FecReassembler::new(params.symbol_size, 64); let out_p = re_p.push(u64::from(syms[1].object_id), &syms[1], 0, 1000); assert_eq!(out_p.as_deref(), Some(ct.as_slice()), "P shard decodes K=1"); + assert_eq!(re_p.recovered_count(), 1); // Decode from Q repair shard only (erasure of source and P) let mut re_q = FecReassembler::new(params.symbol_size, 64); let out_q = re_q.push(u64::from(syms[2].object_id), &syms[2], 0, 1000); assert_eq!(out_q.as_deref(), Some(ct.as_slice()), "Q shard decodes K=1"); + assert_eq!(re_q.recovered_count(), 1); // Wire length mismatch rejection: padded to 1200 instead of trimmed wire len let mut bad_s0 = syms[0].clone(); diff --git a/crates/yip-transport/src/lib.rs b/crates/yip-transport/src/lib.rs index d2df32bd..9a2795c5 100644 --- a/crates/yip-transport/src/lib.rs +++ b/crates/yip-transport/src/lib.rs @@ -438,4 +438,53 @@ mod tests { "object_id must match configured shard" ); } + + #[test] + fn test_transport_symbol_size_and_set_symbol_size() { + let mut t = Transport::new(vec![], 1200); + assert_eq!(t.symbol_size(), 1200); + t.set_symbol_size(1050); + assert_eq!(t.symbol_size(), 1050); + assert_eq!(t.params_for(FlowClass::Realtime).symbol_size, 1050); + } + + #[test] + fn test_transport_observe_ingress_and_fec_recovered_count() { + let mut t = Transport::new(vec![], 1200); + assert_eq!(t.fec_recovered_count(), 0); + + let make_udp = |src_ip: [u8; 4], dst_ip: [u8; 4], sport: u16, dport: u16| { + let mut p = vec![0u8; 100]; + p[0] = 0x45; + p[9] = 17; + p[12..16].copy_from_slice(&src_ip); + p[16..20].copy_from_slice(&dst_ip); + p[20..22].copy_from_slice(&sport.to_be_bytes()); + p[22..24].copy_from_slice(&dport.to_be_bytes()); + p + }; + + let fwd = make_udp([192, 168, 1, 10], [192, 168, 1, 20], 10000, 20000); + let rev = make_udp([192, 168, 1, 20], [192, 168, 1, 10], 20000, 10000); + + let (c0, _) = t.encode(&fwd, &fwd, false, 0); + assert_eq!(c0, FlowClass::Default); + + t.observe_ingress(&rev, false, 10); + t.observe_ingress(&rev, false, 20); + + let (c1, syms) = t.encode(&fwd, &fwd, false, 30); + assert_eq!(c1, FlowClass::Realtime); + assert!(syms.len() >= 2); + + // Receive only the repair symbol (index 1), dropping source symbol 0 + let decoded = t.decode( + u64::from(syms[1].object_id), + &syms[1], + FlowClass::Realtime, + 30, + ); + assert_eq!(decoded.as_deref(), Some(fwd.as_slice())); + assert_eq!(t.fec_recovered_count(), 1); + } } diff --git a/crates/yip-transport/src/plpmtu.rs b/crates/yip-transport/src/plpmtu.rs index 8b34593d..60bfb327 100644 --- a/crates/yip-transport/src/plpmtu.rs +++ b/crates/yip-transport/src/plpmtu.rs @@ -496,4 +496,30 @@ mod tests { assert_eq!(ctrl.probe_interval_ms(), 1000); assert!(!ctrl.is_converged()); } + + #[test] + fn active_probe_id_tracks_probing_and_converged_states() { + let mut ctrl = PlpmtuController::new(); + // Initially in Probing state with active_probe_id = 1 + assert_eq!(ctrl.active_probe_id(), Some(1)); + + let (id1, _, _) = ctrl.on_tick(1000).expect("first probe"); + assert_eq!(id1, 1); + assert_eq!(ctrl.active_probe_id(), Some(1)); + + // Acking 1 transitions to next probe (id 2) + assert_eq!(ctrl.on_ack(id1, 1320), Some(1320)); + assert_eq!(ctrl.active_probe_id(), Some(2)); + + let (id2, _, _) = ctrl.on_tick(2000).expect("second probe"); + assert_eq!(id2, 2); + assert_eq!(ctrl.on_ack(id2, 1400), Some(1400)); + assert_eq!(ctrl.active_probe_id(), Some(3)); + + let (id3, _, _) = ctrl.on_tick(3000).expect("third probe"); + assert_eq!(id3, 3); + assert_eq!(ctrl.on_ack(id3, 1530), Some(1530)); + assert!(ctrl.is_converged()); + assert_eq!(ctrl.active_probe_id(), None); + } } From 697bb0f7de9a455e4ec298c7461551f94e8010ca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 26 Oct 2026 16:09:23 +0000 Subject: [PATCH 2/2] bench(wan): record automated WAN benchmark results [skip ci] --- README.md | 8 +- assets/bench-fec-recovery.svg | 40 +++++----- assets/bench-throughput-loss.svg | 70 +++++++++--------- crates/yip-bench/RESULTS.md | 30 ++++---- .../wan/results/20261026T155743Z/wan.csv | 73 +++++++++++++++++++ crates/yip-bench/wan/results/history.csv | 72 ++++++++++++++++++ .../yip-bench/wan/results/readme-snippet.md | 8 +- 7 files changed, 223 insertions(+), 78 deletions(-) create mode 100644 crates/yip-bench/wan/results/20261026T155743Z/wan.csv diff --git a/README.md b/README.md index 8d1a50fa..2c7f5825 100644 --- a/README.md +++ b/README.md @@ -117,13 +117,13 @@ All benchmark charts are generated deterministically from verified testbed data. -*Two 1-vCPU Debian 13 VPSes, ~54.734 ms apart, 2026-10-24. yip trades raw clean-path throughput for loss resilience — see the FEC row.* +*Two 1-vCPU Debian 13 VPSes, ~58.649 ms apart, 2026-10-26. yip trades raw clean-path throughput for loss resilience — see the FEC row.* | | TCP 1-stream | UDP loss (200M) | effective loss @10% injected | |---|--:|--:|--:| -| **yip** | 254.0 Mbit/s | 0.00% | 0% | -| **WireGuard** | 423.3 Mbit/s | 0.00% | 14% | -| **OpenVPN** | 25.0 Mbit/s | 11.81% | 10% | +| **yip** | 255.4 Mbit/s | 1.76% | 2% | +| **WireGuard** | 375.9 Mbit/s | 0.01% | 12% | +| **OpenVPN** | 21.2 Mbit/s | 0.09% | 17% | diff --git a/assets/bench-fec-recovery.svg b/assets/bench-fec-recovery.svg index 73859dba..ab4c67dd 100644 --- a/assets/bench-fec-recovery.svg +++ b/assets/bench-fec-recovery.svg @@ -45,35 +45,35 @@ 10% Injected Network Loss (netem) Effective Ping Packet Loss % - - + + - - - - + + + + - + - - - + + + - + - - - + + + - - - - 14% effective loss - - 0% loss (100% recovered) + + + + 12% effective loss + + 2% loss (80% recovered) Cauchy RS GF(256): 100% recovery before kernel TCP timeout diff --git a/assets/bench-throughput-loss.svg b/assets/bench-throughput-loss.svg index 161c851b..61f538a2 100644 --- a/assets/bench-throughput-loss.svg +++ b/assets/bench-throughput-loss.svg @@ -20,7 +20,7 @@ OpenVPN - 23× to 138× higher throughput under loss + 53× to 177× higher throughput under loss 0.5 @@ -53,42 +53,42 @@ 10% Netem Injected Packet Loss TCP Goodput (Mbit/s, log scale) - - - + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - 221.3M - - 138× advantage (221.3 vs 1.6 Mbit/s) - - 14.0 Mbit/s - - 0.6 Mbit/s - - - - - 23× higher (14.0 vs 0.6) + + + + + + + + 63.2M + + 53× advantage (63.2 vs 1.2 Mbit/s) + + 88.5 Mbit/s + + 0.5 Mbit/s + + + + + 177× higher (88.5 vs 0.5) NOTE Systematic Reed–Solomon FEC trades minor clean-path overhead for near-complete immunity against loss. diff --git a/crates/yip-bench/RESULTS.md b/crates/yip-bench/RESULTS.md index c6d90624..1dfdfb6b 100644 --- a/crates/yip-bench/RESULTS.md +++ b/crates/yip-bench/RESULTS.md @@ -740,8 +740,8 @@ Regime F delivers: ### Conditions - **Hosts:** `EC2 us-east-1 (t3.small)` ↔ `EC2 us-west-2 (t3.small)` (two 1-vCPU / ~1 GB Debian 13 VPSes, kernel 6.1.0-54-cloud-amd64) -- **Baseline path:** ~54.734 ms RTT, single Gbit links -- **Date / commit:** 2026-10-24T22:11:08Z / `19a499c` +- **Baseline path:** ~58.649 ms RTT, single Gbit links +- **Date / commit:** 2026-10-26T15:57:58Z / `de1a704` - **Host tuning (applied equally, all tunnels):** `net.core.rmem_max=net.core.wmem_max=16 MiB` (so yipd's userspace 4 MiB socket buffers take effect; in-kernel WireGuard is unaffected) - **All tunnels:** UDP outer transport, MTU 1380; yip `transport=raw` (epoll driver — kernel 6.12 has no io_uring multishot recv, #25); WireGuard kernel module; OpenVPN static-key AES-256-GCM @@ -751,10 +751,10 @@ Regime F delivers: | tunnel | TCP 1-stream | TCP 4-stream | UDP goodput | UDP loss | idle RTT | RTT under load | CPU (A, 1 vCPU) | |---|--:|--:|--:|--:|--:|--:|--:| -| baseline (no tunnel) | 286.5 Mbit/s | 926.5 Mbit/s | 200.0 Mbit/s | 0.00% | 54.970 ms | 54.980 ms | 3.3% | -| yip | 254.0 Mbit/s | 301.2 Mbit/s | 200.0 Mbit/s | 0.00% | 55.613 ms | 55.390 ms | 14.7% | -| WireGuard | 423.3 Mbit/s | 928.3 Mbit/s | 200.0 Mbit/s | 0.00% | 55.154 ms | 55.192 ms | 10.7% | -| OpenVPN | 25.0 Mbit/s | 28.4 Mbit/s | 200.0 Mbit/s | 11.81% | 55.059 ms | 55.600 ms | 3.9% | +| baseline (no tunnel) | 420.9 Mbit/s | 731.3 Mbit/s | 200.0 Mbit/s | 0.00% | 54.857 ms | 54.844 ms | 3.9% | +| yip | 255.4 Mbit/s | 375.5 Mbit/s | 200.0 Mbit/s | 1.76% | 57.611 ms | 58.267 ms | 3.6% | +| WireGuard | 375.9 Mbit/s | 927.1 Mbit/s | 200.0 Mbit/s | 0.01% | 61.597 ms | 61.645 ms | 10.6% | +| OpenVPN | 21.2 Mbit/s | 26.9 Mbit/s | 200.0 Mbit/s | 0.09% | 57.782 ms | 57.892 ms | 4.0% | ### Loss resilience (netem injected on the A→B outer path) @@ -763,20 +763,20 @@ Effective end-to-end loss (ping) — lower is better; yip's FEC recovers what th | injected loss | baseline (no tunnel) | yip | WireGuard | OpenVPN | |---|--:|--:|--:|--:| | 0% | 0% | 0% | 0% | 0% | -| 1% | 1% | 0% | 1% | 1% | -| 3% | 5% | 0% | 2% | 3% | -| 5% | 4% | 0% | 4% | 5% | -| 10% | 11% | 0% | 14% | 10% | +| 1% | 1% | 0% | 4% | 0% | +| 3% | 4% | 0% | 2% | 3% | +| 5% | 2% | 1% | 2% | 3% | +| 10% | 17% | 2% | 12% | 17% | TCP goodput under the same injected loss (Mbit/s): | injected loss | baseline (no tunnel) | yip | WireGuard | OpenVPN | |---|--:|--:|--:|--:| -| 0% | 370.4 | 149.7 | 407.7 | 23.7 | -| 1% | 3.7 | 245.7 | 1.9 | 2.4 | -| 3% | 2.1 | 221.3 | 1.6 | 1.2 | -| 5% | 1.5 | 67.0 | 0.8 | 0.7 | -| 10% | 0.8 | 14.0 | 0.6 | 0.7 | +| 0% | 334.9 | 282.0 | 373.9 | 21.4 | +| 1% | 4.5 | 99.8 | 3.3 | 2.7 | +| 3% | 2.1 | 63.2 | 1.2 | 0.9 | +| 5% | 1.6 | 96.3 | 0.8 | 0.8 | +| 10% | 0.6 | 88.5 | 0.5 | 0.6 | ### Reproduce ```sh diff --git a/crates/yip-bench/wan/results/20261026T155743Z/wan.csv b/crates/yip-bench/wan/results/20261026T155743Z/wan.csv new file mode 100644 index 00000000..024f9cac --- /dev/null +++ b/crates/yip-bench/wan/results/20261026T155743Z/wan.csv @@ -0,0 +1,73 @@ +ts,host_pair,commit,tunnel,profile,param,metric,value,conditions +2026-10-26T15:57:58Z,174.129.162.247->34.210.70.41,de1a704,baseline,tcp_throughput,streams=1,mbit_s,420.9,clean +2026-10-26T15:58:11Z,174.129.162.247->34.210.70.41,de1a704,baseline,tcp_throughput,streams=4,mbit_s,731.3,clean +2026-10-26T15:58:22Z,174.129.162.247->34.210.70.41,de1a704,baseline,udp_throughput,offered=200M,mbit_s,200.0,clean +2026-10-26T15:58:22Z,174.129.162.247->34.210.70.41,de1a704,baseline,udp_jitter,offered=200M,ms,0.002,clean +2026-10-26T15:58:22Z,174.129.162.247->34.210.70.41,de1a704,baseline,udp_loss,offered=200M,pct,0.00,clean +2026-10-26T15:58:38Z,174.129.162.247->34.210.70.41,de1a704,baseline,latency,idle,rtt_ms,54.857,clean +2026-10-26T15:58:38Z,174.129.162.247->34.210.70.41,de1a704,baseline,latency,loaded,rtt_ms,54.844,saturated +2026-10-26T15:58:45Z,174.129.162.247->34.210.70.41,de1a704,baseline,cpu_used,tcp_saturate,pct,3.9,sender_host_A_1vcpu +2026-10-26T15:59:04Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_effective,injected=0pct,pct,0,netem_0pct +2026-10-26T15:59:04Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_goodput,injected=0pct,mbit_s,334.9,netem_0pct +2026-10-26T15:59:25Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_effective,injected=1pct,pct,1,netem_1pct +2026-10-26T15:59:25Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_goodput,injected=1pct,mbit_s,4.5,netem_1pct +2026-10-26T15:59:45Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_effective,injected=3pct,pct,4,netem_3pct +2026-10-26T15:59:45Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_goodput,injected=3pct,mbit_s,2.1,netem_3pct +2026-10-26T16:00:06Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_effective,injected=5pct,pct,2,netem_5pct +2026-10-26T16:00:06Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_goodput,injected=5pct,mbit_s,1.6,netem_5pct +2026-10-26T16:00:28Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_effective,injected=10pct,pct,17,netem_10pct +2026-10-26T16:00:28Z,174.129.162.247->34.210.70.41,de1a704,baseline,loss_goodput,injected=10pct,mbit_s,0.6,netem_10pct +2026-10-26T16:00:41Z,174.129.162.247->34.210.70.41,de1a704,yip,tcp_throughput,streams=1,mbit_s,255.4,clean +2026-10-26T16:00:54Z,174.129.162.247->34.210.70.41,de1a704,yip,tcp_throughput,streams=4,mbit_s,375.5,clean +2026-10-26T16:01:05Z,174.129.162.247->34.210.70.41,de1a704,yip,udp_throughput,offered=200M,mbit_s,200.0,clean +2026-10-26T16:01:05Z,174.129.162.247->34.210.70.41,de1a704,yip,udp_jitter,offered=200M,ms,0.006,clean +2026-10-26T16:01:05Z,174.129.162.247->34.210.70.41,de1a704,yip,udp_loss,offered=200M,pct,1.76,clean +2026-10-26T16:01:22Z,174.129.162.247->34.210.70.41,de1a704,yip,latency,idle,rtt_ms,57.611,clean +2026-10-26T16:01:22Z,174.129.162.247->34.210.70.41,de1a704,yip,latency,loaded,rtt_ms,58.267,saturated +2026-10-26T16:01:29Z,174.129.162.247->34.210.70.41,de1a704,yip,cpu_used,tcp_saturate,pct,3.6,sender_host_A_1vcpu +2026-10-26T16:01:48Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_effective,injected=0pct,pct,0,netem_0pct +2026-10-26T16:01:48Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_goodput,injected=0pct,mbit_s,282.0,netem_0pct +2026-10-26T16:02:08Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_effective,injected=1pct,pct,0,netem_1pct +2026-10-26T16:02:08Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_goodput,injected=1pct,mbit_s,99.8,netem_1pct +2026-10-26T16:02:29Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_effective,injected=3pct,pct,0,netem_3pct +2026-10-26T16:02:29Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_goodput,injected=3pct,mbit_s,63.2,netem_3pct +2026-10-26T16:02:49Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_effective,injected=5pct,pct,1,netem_5pct +2026-10-26T16:02:49Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_goodput,injected=5pct,mbit_s,96.3,netem_5pct +2026-10-26T16:03:10Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_effective,injected=10pct,pct,2,netem_10pct +2026-10-26T16:03:10Z,174.129.162.247->34.210.70.41,de1a704,yip,loss_goodput,injected=10pct,mbit_s,88.5,netem_10pct +2026-10-26T16:03:23Z,174.129.162.247->34.210.70.41,de1a704,wireguard,tcp_throughput,streams=1,mbit_s,375.9,clean +2026-10-26T16:03:36Z,174.129.162.247->34.210.70.41,de1a704,wireguard,tcp_throughput,streams=4,mbit_s,927.1,clean +2026-10-26T16:03:47Z,174.129.162.247->34.210.70.41,de1a704,wireguard,udp_throughput,offered=200M,mbit_s,200.0,clean +2026-10-26T16:03:47Z,174.129.162.247->34.210.70.41,de1a704,wireguard,udp_jitter,offered=200M,ms,0.013,clean +2026-10-26T16:03:47Z,174.129.162.247->34.210.70.41,de1a704,wireguard,udp_loss,offered=200M,pct,0.01,clean +2026-10-26T16:04:04Z,174.129.162.247->34.210.70.41,de1a704,wireguard,latency,idle,rtt_ms,61.597,clean +2026-10-26T16:04:04Z,174.129.162.247->34.210.70.41,de1a704,wireguard,latency,loaded,rtt_ms,61.645,saturated +2026-10-26T16:04:11Z,174.129.162.247->34.210.70.41,de1a704,wireguard,cpu_used,tcp_saturate,pct,10.6,sender_host_A_1vcpu +2026-10-26T16:04:30Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_effective,injected=0pct,pct,0,netem_0pct +2026-10-26T16:04:30Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_goodput,injected=0pct,mbit_s,373.9,netem_0pct +2026-10-26T16:04:51Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_effective,injected=1pct,pct,4,netem_1pct +2026-10-26T16:04:51Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_goodput,injected=1pct,mbit_s,3.3,netem_1pct +2026-10-26T16:05:11Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_effective,injected=3pct,pct,2,netem_3pct +2026-10-26T16:05:11Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_goodput,injected=3pct,mbit_s,1.2,netem_3pct +2026-10-26T16:05:32Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_effective,injected=5pct,pct,2,netem_5pct +2026-10-26T16:05:32Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_goodput,injected=5pct,mbit_s,0.8,netem_5pct +2026-10-26T16:05:52Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_effective,injected=10pct,pct,12,netem_10pct +2026-10-26T16:05:52Z,174.129.162.247->34.210.70.41,de1a704,wireguard,loss_goodput,injected=10pct,mbit_s,0.5,netem_10pct +2026-10-26T16:06:06Z,174.129.162.247->34.210.70.41,de1a704,openvpn,tcp_throughput,streams=1,mbit_s,21.2,clean +2026-10-26T16:06:19Z,174.129.162.247->34.210.70.41,de1a704,openvpn,tcp_throughput,streams=4,mbit_s,26.9,clean +2026-10-26T16:06:30Z,174.129.162.247->34.210.70.41,de1a704,openvpn,udp_throughput,offered=200M,mbit_s,200.0,clean +2026-10-26T16:06:30Z,174.129.162.247->34.210.70.41,de1a704,openvpn,udp_jitter,offered=200M,ms,0.034,clean +2026-10-26T16:06:30Z,174.129.162.247->34.210.70.41,de1a704,openvpn,udp_loss,offered=200M,pct,0.09,clean +2026-10-26T16:06:46Z,174.129.162.247->34.210.70.41,de1a704,openvpn,latency,idle,rtt_ms,57.782,clean +2026-10-26T16:06:46Z,174.129.162.247->34.210.70.41,de1a704,openvpn,latency,loaded,rtt_ms,57.892,saturated +2026-10-26T16:06:53Z,174.129.162.247->34.210.70.41,de1a704,openvpn,cpu_used,tcp_saturate,pct,4.0,sender_host_A_1vcpu +2026-10-26T16:07:13Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_effective,injected=0pct,pct,0,netem_0pct +2026-10-26T16:07:13Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_goodput,injected=0pct,mbit_s,21.4,netem_0pct +2026-10-26T16:07:33Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_effective,injected=1pct,pct,0,netem_1pct +2026-10-26T16:07:33Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_goodput,injected=1pct,mbit_s,2.7,netem_1pct +2026-10-26T16:07:53Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_effective,injected=3pct,pct,3,netem_3pct +2026-10-26T16:07:53Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_goodput,injected=3pct,mbit_s,0.9,netem_3pct +2026-10-26T16:08:14Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_effective,injected=5pct,pct,3,netem_5pct +2026-10-26T16:08:14Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_goodput,injected=5pct,mbit_s,0.8,netem_5pct +2026-10-26T16:08:34Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_effective,injected=10pct,pct,17,netem_10pct +2026-10-26T16:08:34Z,174.129.162.247->34.210.70.41,de1a704,openvpn,loss_goodput,injected=10pct,mbit_s,0.6,netem_10pct diff --git a/crates/yip-bench/wan/results/history.csv b/crates/yip-bench/wan/results/history.csv index e1689043..579b0d93 100644 --- a/crates/yip-bench/wan/results/history.csv +++ b/crates/yip-bench/wan/results/history.csv @@ -1007,3 +1007,75 @@ ts,host_pair,commit,tunnel,profile,param,metric,value,conditions 2026-10-24T22:22:01Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),19a499c,openvpn,loss_goodput,injected=5pct,mbit_s,0.7,netem_5pct 2026-10-24T22:22:25Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),19a499c,openvpn,loss_effective,injected=10pct,pct,10,netem_10pct 2026-10-24T22:22:25Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),19a499c,openvpn,loss_goodput,injected=10pct,mbit_s,0.7,netem_10pct +2026-10-26T15:57:58Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,tcp_throughput,streams=1,mbit_s,420.9,clean +2026-10-26T15:58:11Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,tcp_throughput,streams=4,mbit_s,731.3,clean +2026-10-26T15:58:22Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,udp_throughput,offered=200M,mbit_s,200.0,clean +2026-10-26T15:58:22Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,udp_jitter,offered=200M,ms,0.002,clean +2026-10-26T15:58:22Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,udp_loss,offered=200M,pct,0.00,clean +2026-10-26T15:58:38Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,latency,idle,rtt_ms,54.857,clean +2026-10-26T15:58:38Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,latency,loaded,rtt_ms,54.844,saturated +2026-10-26T15:58:45Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,cpu_used,tcp_saturate,pct,3.9,sender_host_A_1vcpu +2026-10-26T15:59:04Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_effective,injected=0pct,pct,0,netem_0pct +2026-10-26T15:59:04Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_goodput,injected=0pct,mbit_s,334.9,netem_0pct +2026-10-26T15:59:25Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_effective,injected=1pct,pct,1,netem_1pct +2026-10-26T15:59:25Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_goodput,injected=1pct,mbit_s,4.5,netem_1pct +2026-10-26T15:59:45Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_effective,injected=3pct,pct,4,netem_3pct +2026-10-26T15:59:45Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_goodput,injected=3pct,mbit_s,2.1,netem_3pct +2026-10-26T16:00:06Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_effective,injected=5pct,pct,2,netem_5pct +2026-10-26T16:00:06Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_goodput,injected=5pct,mbit_s,1.6,netem_5pct +2026-10-26T16:00:28Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_effective,injected=10pct,pct,17,netem_10pct +2026-10-26T16:00:28Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,baseline,loss_goodput,injected=10pct,mbit_s,0.6,netem_10pct +2026-10-26T16:00:41Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,tcp_throughput,streams=1,mbit_s,255.4,clean +2026-10-26T16:00:54Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,tcp_throughput,streams=4,mbit_s,375.5,clean +2026-10-26T16:01:05Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,udp_throughput,offered=200M,mbit_s,200.0,clean +2026-10-26T16:01:05Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,udp_jitter,offered=200M,ms,0.006,clean +2026-10-26T16:01:05Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,udp_loss,offered=200M,pct,1.76,clean +2026-10-26T16:01:22Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,latency,idle,rtt_ms,57.611,clean +2026-10-26T16:01:22Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,latency,loaded,rtt_ms,58.267,saturated +2026-10-26T16:01:29Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,cpu_used,tcp_saturate,pct,3.6,sender_host_A_1vcpu +2026-10-26T16:01:48Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_effective,injected=0pct,pct,0,netem_0pct +2026-10-26T16:01:48Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_goodput,injected=0pct,mbit_s,282.0,netem_0pct +2026-10-26T16:02:08Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_effective,injected=1pct,pct,0,netem_1pct +2026-10-26T16:02:08Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_goodput,injected=1pct,mbit_s,99.8,netem_1pct +2026-10-26T16:02:29Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_effective,injected=3pct,pct,0,netem_3pct +2026-10-26T16:02:29Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_goodput,injected=3pct,mbit_s,63.2,netem_3pct +2026-10-26T16:02:49Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_effective,injected=5pct,pct,1,netem_5pct +2026-10-26T16:02:49Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_goodput,injected=5pct,mbit_s,96.3,netem_5pct +2026-10-26T16:03:10Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_effective,injected=10pct,pct,2,netem_10pct +2026-10-26T16:03:10Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,yip,loss_goodput,injected=10pct,mbit_s,88.5,netem_10pct +2026-10-26T16:03:23Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,tcp_throughput,streams=1,mbit_s,375.9,clean +2026-10-26T16:03:36Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,tcp_throughput,streams=4,mbit_s,927.1,clean +2026-10-26T16:03:47Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,udp_throughput,offered=200M,mbit_s,200.0,clean +2026-10-26T16:03:47Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,udp_jitter,offered=200M,ms,0.013,clean +2026-10-26T16:03:47Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,udp_loss,offered=200M,pct,0.01,clean +2026-10-26T16:04:04Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,latency,idle,rtt_ms,61.597,clean +2026-10-26T16:04:04Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,latency,loaded,rtt_ms,61.645,saturated +2026-10-26T16:04:11Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,cpu_used,tcp_saturate,pct,10.6,sender_host_A_1vcpu +2026-10-26T16:04:30Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_effective,injected=0pct,pct,0,netem_0pct +2026-10-26T16:04:30Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_goodput,injected=0pct,mbit_s,373.9,netem_0pct +2026-10-26T16:04:51Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_effective,injected=1pct,pct,4,netem_1pct +2026-10-26T16:04:51Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_goodput,injected=1pct,mbit_s,3.3,netem_1pct +2026-10-26T16:05:11Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_effective,injected=3pct,pct,2,netem_3pct +2026-10-26T16:05:11Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_goodput,injected=3pct,mbit_s,1.2,netem_3pct +2026-10-26T16:05:32Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_effective,injected=5pct,pct,2,netem_5pct +2026-10-26T16:05:32Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_goodput,injected=5pct,mbit_s,0.8,netem_5pct +2026-10-26T16:05:52Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_effective,injected=10pct,pct,12,netem_10pct +2026-10-26T16:05:52Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,wireguard,loss_goodput,injected=10pct,mbit_s,0.5,netem_10pct +2026-10-26T16:06:06Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,tcp_throughput,streams=1,mbit_s,21.2,clean +2026-10-26T16:06:19Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,tcp_throughput,streams=4,mbit_s,26.9,clean +2026-10-26T16:06:30Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,udp_throughput,offered=200M,mbit_s,200.0,clean +2026-10-26T16:06:30Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,udp_jitter,offered=200M,ms,0.034,clean +2026-10-26T16:06:30Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,udp_loss,offered=200M,pct,0.09,clean +2026-10-26T16:06:46Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,latency,idle,rtt_ms,57.782,clean +2026-10-26T16:06:46Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,latency,loaded,rtt_ms,57.892,saturated +2026-10-26T16:06:53Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,cpu_used,tcp_saturate,pct,4.0,sender_host_A_1vcpu +2026-10-26T16:07:13Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_effective,injected=0pct,pct,0,netem_0pct +2026-10-26T16:07:13Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_goodput,injected=0pct,mbit_s,21.4,netem_0pct +2026-10-26T16:07:33Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_effective,injected=1pct,pct,0,netem_1pct +2026-10-26T16:07:33Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_goodput,injected=1pct,mbit_s,2.7,netem_1pct +2026-10-26T16:07:53Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_effective,injected=3pct,pct,3,netem_3pct +2026-10-26T16:07:53Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_goodput,injected=3pct,mbit_s,0.9,netem_3pct +2026-10-26T16:08:14Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_effective,injected=5pct,pct,3,netem_5pct +2026-10-26T16:08:14Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_goodput,injected=5pct,mbit_s,0.8,netem_5pct +2026-10-26T16:08:34Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_effective,injected=10pct,pct,17,netem_10pct +2026-10-26T16:08:34Z,EC2 us-east-1 (t3.small)->EC2 us-west-2 (t3.small),de1a704,openvpn,loss_goodput,injected=10pct,mbit_s,0.6,netem_10pct diff --git a/crates/yip-bench/wan/results/readme-snippet.md b/crates/yip-bench/wan/results/readme-snippet.md index 3aee4565..63235549 100644 --- a/crates/yip-bench/wan/results/readme-snippet.md +++ b/crates/yip-bench/wan/results/readme-snippet.md @@ -1,8 +1,8 @@ -*Two 1-vCPU Debian 13 VPSes, ~54.734 ms apart, 2026-10-24. yip trades raw clean-path throughput for loss resilience — see the FEC row.* +*Two 1-vCPU Debian 13 VPSes, ~58.649 ms apart, 2026-10-26. yip trades raw clean-path throughput for loss resilience — see the FEC row.* | | TCP 1-stream | UDP loss (200M) | effective loss @10% injected | |---|--:|--:|--:| -| **yip** | 254.0 Mbit/s | 0.00% | 0% | -| **WireGuard** | 423.3 Mbit/s | 0.00% | 14% | -| **OpenVPN** | 25.0 Mbit/s | 11.81% | 10% | +| **yip** | 255.4 Mbit/s | 1.76% | 2% | +| **WireGuard** | 375.9 Mbit/s | 0.01% | 12% | +| **OpenVPN** | 21.2 Mbit/s | 0.09% | 17% |