August 29–31, 2026
Primary-Link Failover, a Real Latency Mystery Finally Closed, and a New Job
Three days that closed out a genuinely months-old mlvpn-rs mystery, shipped a brand-new way to run the tunnel, and turned up a real slowdown on real hardware that isn't fully fixed yet. Plus a personal update: tomorrow I start a new part-time job.
Closing a mystery that's been open for months
Long-time readers of this blog (or anyone who's heard me complain about it in person) know about
the mystery where mlvpn-rs seemed to lose data under load, even though every counter it kept on
itself stayed at zero the whole time. It survived several releases without me ever finding the real
cause. It's closed now, and it turns out nothing was ever actually lost — it was delay, and
everything downstream was badly misreading that delay as loss.
The culprit was the part of the tunnel that puts packets back in the right order when they arrive
out of sequence — think of it as a bouncer at the door, holding a packet back briefly if it looks
like it arrived ahead of one that should have come first. The bug: it was waiting for a specific
packet that almost never actually showed up, so it ended up holding nearly everything back for
almost the full delay window, every time, in both directions. That added about 110 milliseconds of
pure, needless delay — exactly the kind of thing that can look like lost data to anything timing
a connection.
I fixed that in one release, watched it work great right after a fresh restart — then watched it
quietly break itself again a couple minutes later. The fix only worked until the tunnel's routine
security refresh (every two minutes by default), which reset some internal counting the fix
depended on. So the first refresh after a restart silently undid the fix, and it got slightly worse
with every refresh after that. I caught this by measuring a healthy connection right after restart,
then watching it degrade back to the old bad numbers a few minutes later, while a plain ping on the
same physical link never budged. Fixed it properly this time, and confirmed it by sitting there and
watching the connection survive a real security refresh and stay healthy the whole time.
A new way to run the tunnel: one link at a time, with failover
mlvpn-rs has always worked by spreading traffic across every internet connection it's given at
once, to add their speeds together. That's great when every link is roughly similar, but not
always what you want — sometimes one connection is simply better, and you'd rather use it
exclusively and only fall back to the other one if it actually drops. Built exactly that: a new
mode where one link is designated primary and carries everything, with automatic failover to
another link the moment the primary looks unhealthy, plus a variant where one side of the tunnel
can tell the other which link it's actually using, so both ends make the same choice instead of
guessing independently. Deployed it the same night on my own real home-to-cloud router pair — not
a lab test, the actual pair that's been carrying real traffic this whole time.
Small companion feature that landed the same night: both sides of a tunnel now show each other
their real packet-size setting live, so a mismatch between the two ends is something you can
actually see instead of having to guess at from symptoms.
A real slowdown, caught live, not yet fully fixed
While all that was going out to production, I went looking at exactly how efficiently the program
was using the computer's processor on the real routers. What I found: it was spending somewhere
around 75 to 80 percent of its time waiting in line for access to shared data, instead of actually
moving traffic. That's a real bottleneck, capping real speed well below what the connections could
actually carry, and it was invisible without watching the program run live — nothing about it
showed up as an error or lost data anywhere.
I shipped two same-night follow-up fixes that each cut down on how often that happens. Being
straightforward about where this stands: it's better, but it isn't fully resolved yet. This is
exactly the kind of bug where I'd rather say "meaningfully improved, more work still to do" than
claim it's solved before I've actually proven that with more real-world testing.
Smaller things, and a personal update
Also in this stretch: raised the size of an internal holding area the tunnel uses on its way out
to the network, since the old limit could start dropping bursts of traffic before the rest of the
program even got a chance to handle them — cheap insurance against a whole class of bursty-traffic
problems. And fixed a smaller but real annoyance in how releases get built: tagging a release was
always treated as something brand new, so every tagged release was forced through a slow, from-
scratch rebuild even when the exact same code had just been built minutes earlier. Now a tagged
release reuses that earlier work instead of redoing it.
On the personal side: tomorrow I start a new part-time job as a sales representative at the Ace
Hardware here in Zion. Different kind of work than anything above — good to have something that
isn't a keyboard for a few hours a week.