Understanding HAProxy QUIC architecture and CID-based routing

Hello,

I am studying the HAProxy QUIC implementation and trying to understand the steady-state packet handling architecture.

From reading the source code (quic_rx.c, quic_tx.c, quic_conn.c, mux_quic.c, quic_cid.c), it seems that HAProxy implements a full QUIC stack where incoming UDP datagrams are:

  1. demultiplexed by CID

  2. header protection removed

  3. decrypted and parsed into QUIC frames

  4. processed by the connection state machine (ACK/loss/congestion control)

  5. delivered to the QUIC mux / HTTP layer

I also noticed that CIDs are stored in sharded trees (quic_cid.c) and used to dispatch packets to the correct thread and connection.

I would like to confirm whether my understanding is correct:

  1. In steady state, does HAProxy always decrypt QUIC packets and process them as part of its own QUIC stack?

  2. Or are there any fast-path mechanisms where HAProxy forwards encrypted QUIC packets to the backend without terminating QUIC?

  3. Is the primary role of CID lookup mainly for connection demultiplexing and thread dispatch, rather than routing packets to backend servers?

I am mainly interested in understanding the architecture rather than configuration details.

Thank you!

Haproxy is always terminating QUIC in it its entirety, normalising the HTTP transaction into a HTTP version agnostic transaction (internally called HTX).

There is no other mode or configuration; there is no QUIC passthrough of any kind.