The engine decrypts inbound ESP on the ARMADA: an accepted association, decrypting in hardware¶
2026-10-14, the XGS 136, step 5 of the offload plan, third slice.
Slice 2 proved the engine accepts a GCM SA_ADD;
this one accepts a real offered association and keeps it, and the coprocessor's crypto engine then
decrypts the tunnel's inbound ESP in hardware.
What was added¶
An SA table (the handle is the index plus one, the OCTEON TX convention), the SA_ADD/SA_DEL
builders, and the accept path in if_sa_newkey: when dev.npuep.0.ipsec.accept_decrypt is set and
the kernel offers a GCM decrypt association to the port that owns its destination, the driver
installs it on the engine, keeps it, and returns success - so the kernel hands that association's
traffic to the driver instead of decrypting it in software. if_sa_deinstall takes it back out. The
switch is off by default, because without the receive termination the decrypted frames are not yet
delivered - this slice is to see the decrypt happen, not to carry the tunnel.
Measured, on a live tunnel¶
A real IPsec tunnel between the appliance and a software peer, AES-GCM-16, both ends established and
the child SA installed. With accept_decrypt set, the driver accepted the two decrypt associations
(SA_ADD accepted by the engine). The peer then drove a burst of ESP through the tunnel, and on the
appliance two counters moved by exactly the burst:
So the fast path matched the SPI of the accepted association and handed each inbound ESP frame to the crypto engine, which decrypted it in hardware. Inbound IPsec decrypt is offloaded on the ARMADA.
What is next: the receive termination¶
After the decrypt, no onward counter moved - FROM_IPSEC_DECR_TO_KERNEL and ..._TO_WIRE stayed
zero, and the decrypted frame did not reach the host. On this family an accepted inbound association
decrypts in hardware, but the decrypted frame is not punted to the host by default; it is consumed in
the fast path. The receive-termination slice is to make the host take the decrypted frame - the ESP
handed up with its outer header re-templated and the inner packet in the clear, carrying the handle
in its metadata, as the OCTEON TX driver's octep_ipsec_rx does - terminate the ESP and deliver the
inner packet, filtered on enc0. That is where the per-frame crypto marker is read. Then the transmit
envelope and the outbound sequence hand-over, and NAT-T, ESN, the replay window, CBC with HMAC, and
IPv6. ipsec.flows 2 is never set here.
The discussion of this page is held in the project's GitHub Discussions. Showing it here loads giscus from giscus.app and GitHub, and writing in it needs a GitHub account - what that means.