Two labels get used as if they were the same thing: hardware accelerated and kernel offloaded. One describes which instructions a library's AES routine executes, and the other describes where packet processing happens. A VPN can have the first without the second, the second without the first, or both at once. Anything you decide about performance has to start by naming which of the two you are actually changing.

Two axes, not one score

The first axis is implementation: does the code doing AES-256-GCM dispatch to a version that uses the processor's dedicated instructions, or to a portable routine that runs them as ordinary arithmetic. That choice lives inside the cryptographic library and is made when it initializes.

The second axis is placement: does the packet traverse the kernel's transform path, or does a user-space daemon read from a tunnel device, encrypt, and write back out.

Neither axis constrains the other. A user-space VPN on a CPU with AES instructions can be using them the whole time, and a kernel path on a CPU without them falls back to a software implementation. The labels in vendor material rarely make that distinction, which is why tuning advice copied between the two situations so often does nothing.

Axis one: which code performs the encryption

OpenSSL detects processor features during initialization and uses the result to pick optimized code paths, as the x86 capability documentation describes. AES-NI is one of the documented capabilities behind that dispatch. Nothing about this requires the library to become a kernel component.

Confirm the feature is visible to the process before assuming the fast path is taken. On Linux the flags field of /proc/cpuinfo is the source, and inside a guest it reflects what the hypervisor exposes rather than the physical host's model name.

grep -m1 '^flags' /proc/cpuinfo | grep -o '\baes\b'
openssl list -providers -verbose

The second command names the providers loaded in that build. It does not tell you which library the VPN service linked, and a host can carry two OpenSSL installations while the running process uses only one of them.

Axis two: where the packet path runs

Kernel placement means the transform happens in the kernel's own IPsec machinery or inside an in-kernel tunnel driver, so packets do not need a round trip through a user-space process for every batch. That can cut copies and context switches, and it can spread work across cores in ways a single-threaded daemon cannot. It also moves the counters and traces you will read when throughput drops, because the work now happens on the far side of a boundary you do not control. Treat that as a debugging cost, not only a performance decision.

It does not create instruction support, configure a cipher, or make an existing route work.

Virtualization adds a wrinkle on this axis too. A guest may be given a masked CPU model that hides features the host has, and a nested guest may see less again. Read the capability view from inside the environment where the VPN actually runs, not from the hypervisor console.

What each choice buys, and what it cannot

The practical question is where time goes. If a single busy thread, repeated buffer copies or a per-packet syscall pattern limits throughput, moving the transform into a path that removes those costs can help, provided the kernel implements the transform you need.

If the limit is a congested uplink, a lossy path, a long round trip, a saturated destination service or one thread pinned to one core, placement changes nothing that matters. The same holds for instruction selection: AES on dedicated hardware cannot repair a missing route, and it will not help if the tunnel is idle because name resolution is failing.

Where both apply, they compose. A kernel path can use the same instruction-level dispatch inside the kernel's crypto API, and a user-space path with a well-chosen library is already using it. The decision is not which one is faster in the abstract; it is which cost you have evidence for.

Record the four facts before you change anything

Write down the service binary and the crypto library it links, since those decide axis one. Then record the negotiated data protection, because a cipher without a dedicated instruction path behaves differently from one with it, and the suite is chosen by both peers.

Next, the capability view from inside the running environment, and finally the active packet path with evidence that the mode you think is enabled really is. A loaded module is not proof that a profile uses it, and a configuration line is not proof that the kernel accepted it.

Change one thing, then compare against a consistent workload with the same endpoints and the same direction of transfer. A speed claim you did not measure is worth less than a note saying the backend was never in doubt.

Winndannde jowitiiɗe heen