Windows Version
Microsoft Windows [Version 10.0.26200.9106]
WSL Version
2.7.10.0
Are you using WSL 1 or WSL 2?
Kernel Version
6.18.33.2-2
Distro Version
Ubuntu 24.04 (Noble Numbat)
Other Software
openvpn3-linux v26-3 and v27.1 (OpenVPN core 3.11.5 / 3.11.7) — affected, but only
as a symptom. The benchmark below reproduces the underlying behaviour with nothing
installed beyond Python 3.
Repro Steps
bind() takes ~10 ms on every socket family under WSL2, while socket() creation
is free. This is not specific to networking mode — a private (non-mirrored) network
namespace shows the same cost.
.wslconfig:
[wsl2]
networkingMode=mirrored
dnsTunneling=true
firewall=false
autoProxy=true
[experimental]
hostAddressLoopback=true
- Save and run this benchmark.
socket() is timed separately as a control:
import socket, time, statistics, os
N = 200
def bench(label, make, act):
ts = []
for _ in range(N):
s = make()
t0 = time.perf_counter(); act(s); t1 = time.perf_counter()
ts.append((t1 - t0) * 1000); s.close()
ts.sort()
print(f"{label:36s} median {statistics.median(ts):7.3f} ms min {ts[0]:6.3f} max {ts[-1]:7.3f}")
bench("AF_NETLINK bind()",
lambda: socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, socket.NETLINK_ROUTE),
lambda s: s.bind((0, 0)))
bench("AF_NETLINK socket() only (control)",
lambda: socket.socket(socket.AF_NETLINK, socket.SOCK_RAW, socket.NETLINK_ROUTE),
lambda s: None)
bench("AF_UNIX bind() (abstract)",
lambda: socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM),
lambda s: s.bind("\0b%d_%d" % (os.getpid(), time.time_ns())))
bench("AF_INET/UDP bind()",
lambda: socket.socket(socket.AF_INET, socket.SOCK_DGRAM),
lambda s: s.bind(("127.0.0.1", 0)))
- To separate mirrored-mode cost from baseline cost, run the same script again
inside a private network namespace, which is not mirrored:
sudo unshare -n -- sh -c "ip link set lo up; exec python3 bench.py"
Expected Behavior
bind() on AF_UNIX and AF_NETLINK involves no network stack coordination and
should complete in microseconds, as it does on a conventional Linux kernel.
AF_INET bind() to an ephemeral port on loopback should likewise be
inexpensive.
Actual Behavior
host netns private netns
AF_NETLINK bind() 10.098 ms 10.092 ms <- unchanged
AF_UNIX bind() 10.150 ms 10.495 ms <- unchanged
AF_INET/UDP bind() 21.141 ms 10.500 ms <- halved
socket() only (control) 0.000 ms 0.000 ms
Two independent effects:
- A baseline ~10 ms
bind() cost on every socket family, identical inside a
private namespace. Not related to mirrored networking. This is the one with
real impact.
- Mirrored mode adds a second ~10 ms increment, but only to
AF_INET
(21 ms vs 10.5 ms). Plausibly port coordination with the Windows host —
AF_UNIX and AF_NETLINK have no ports and are unaffected.
socket() measuring ~0 ms rules out general syscall overhead.
Correction (see comment below). I originally wrote that the ~10 ms figure
looked like a scheduler tick. That is wrong — this kernel is CONFIG_HZ=250
(a 4 ms tick), and 10 ms is not a multiple of 4 ms. A 400-sample histogram is
sharply unimodal at 10–12 ms for AF_NETLINK (97% within 8–12 ms) and at
20–22 ms for AF_INET (90%), i.e. almost exactly 2×. That points at one and
two instances of a fixed ~10 ms synchronous cost rather than anything
timer-aligned. Confirmed independently of Python via strace -T on
openvpn3-service-netcfg (C++): 901 bind() calls, mean 9.1 ms, max 10.8 ms.
Real-world impact. openvpn3-linux cannot establish a tunnel at all. Its
openvpn3-service-netcfg opens a fresh AF_NETLINK socket per configuration
operation; with a split-tunnel profile pushing ~900 routes (a commonplace
corporate configuration) that is ~900 × ~10 ms ≈ 9 s, against a fixed 5 s D-Bus
timeout on its Establish() call:
901 bind() calls mean 9.1 ms max 10.8 ms total 8.183 s
Error calling NetCfgDevice::Establish(): ... Timeout was reached
Failed configuring TUN device (TUN_IFACE_CREATE)
507 of the 900 operations had completed when the caller aborted. The identical
route set installed through a single reused socket (ip -batch) takes ~0.4 s, so
the per-bind() cost is the entire difference between working and not working.
Switching to NAT mode does not help, since the baseline cost is not
mirrored-mode related. The per-socket churn is also being reported to
openvpn3-linux separately.
Diagnostic Logs
Per-operation pattern from strace -f -tt -T on openvpn3-service-netcfg,
repeating once per route:
socket(AF_UNIX, SOCK_DGRAM) -> ioctl(SIOCGIFINDEX) -> close
socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)
-> setsockopt(SO_SNDBUF) -> setsockopt(SO_RCVBUF)
-> bind() <-- ~9-10 ms, dominant cost
-> getsockname -> sendmsg -> recvmsg -> close
Within the 5 s Establish() window: 507 bind() calls, 4.601 s in bind()
alone out of 4.939 s total worker syscall time — 93% of the budget.
Possibly related, though a different mechanism: #41443 (mirrored networking drops
replies from a TUN-based VPN adapter). Same kernel and distro; that one is about
packet delivery, this one about syscall latency.
Windows Version
Microsoft Windows [Version 10.0.26200.9106]
WSL Version
2.7.10.0
Are you using WSL 1 or WSL 2?
Kernel Version
6.18.33.2-2
Distro Version
Ubuntu 24.04 (Noble Numbat)
Other Software
openvpn3-linux v26-3 and v27.1 (OpenVPN core 3.11.5 / 3.11.7) — affected, but only
as a symptom. The benchmark below reproduces the underlying behaviour with nothing
installed beyond Python 3.
Repro Steps
bind()takes ~10 ms on every socket family under WSL2, whilesocket()creationis free. This is not specific to networking mode — a private (non-mirrored) network
namespace shows the same cost.
.wslconfig:socket()is timed separately as a control:inside a private network namespace, which is not mirrored:
sudo unshare -n -- sh -c "ip link set lo up; exec python3 bench.py"Expected Behavior
bind()onAF_UNIXandAF_NETLINKinvolves no network stack coordination andshould complete in microseconds, as it does on a conventional Linux kernel.
AF_INETbind()to an ephemeral port on loopback should likewise beinexpensive.
Actual Behavior
Two independent effects:
bind()cost on every socket family, identical inside aprivate namespace. Not related to mirrored networking. This is the one with
real impact.
AF_INET(21 ms vs 10.5 ms). Plausibly port coordination with the Windows host —
AF_UNIXandAF_NETLINKhave no ports and are unaffected.socket()measuring ~0 ms rules out general syscall overhead.Real-world impact.
openvpn3-linuxcannot establish a tunnel at all. Itsopenvpn3-service-netcfgopens a freshAF_NETLINKsocket per configurationoperation; with a split-tunnel profile pushing ~900 routes (a commonplace
corporate configuration) that is ~900 × ~10 ms ≈ 9 s, against a fixed 5 s D-Bus
timeout on its
Establish()call:507 of the 900 operations had completed when the caller aborted. The identical
route set installed through a single reused socket (
ip -batch) takes ~0.4 s, sothe per-
bind()cost is the entire difference between working and not working.Switching to NAT mode does not help, since the baseline cost is not
mirrored-mode related. The per-socket churn is also being reported to
openvpn3-linux separately.
Diagnostic Logs
Per-operation pattern from
strace -f -tt -Tonopenvpn3-service-netcfg,repeating once per route:
Within the 5 s
Establish()window: 507bind()calls, 4.601 s inbind()alone out of 4.939 s total worker syscall time — 93% of the budget.
Possibly related, though a different mechanism: #41443 (mirrored networking drops
replies from a TUN-based VPN adapter). Same kernel and distro; that one is about
packet delivery, this one about syscall latency.