mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-06 15:17:01 +02:00
MEDIUM: quic: Heavy task mode during handshake
Add a new pool for the CRYPTO data frames received in order. Add ->rx.crypto_frms list to each encryption level to store such frames when they are received in order from qc_handle_crypto_frm(). Also set the handshake task (qc_conn_io_cb()) in heavy task mode from this function after having received such frames. When this task detects that it is set in heavy mode, it calls qc_ssl_provide_all_quic_data() newly implemented function to provide the CRYPTO data to the TLS task. Modify quic_conn_enc_level_uninit() to release these CRYPTO frames when releasing the encryption level they are in relation with.
This commit is contained in:
parent
84d26bcf3f
commit
94d20be138
@ -35,6 +35,7 @@
|
||||
#include <haproxy/quic_stream-t.h>
|
||||
|
||||
extern struct pool_head *pool_head_quic_frame;
|
||||
extern struct pool_head *pool_head_qf_crypto;
|
||||
|
||||
/* forward declarations from xprt-quic */
|
||||
struct quic_arngs;
|
||||
@ -144,6 +145,7 @@ struct qf_stop_sending {
|
||||
};
|
||||
|
||||
struct qf_crypto {
|
||||
struct list list;
|
||||
uint64_t offset;
|
||||
uint64_t len;
|
||||
const struct quic_enc_level *qel;
|
||||
|
@ -34,6 +34,7 @@ int qc_ssl_provide_quic_data(struct ncbuf *ncbuf,
|
||||
enum ssl_encryption_level_t level,
|
||||
struct ssl_sock_ctx *ctx,
|
||||
const unsigned char *data, size_t len);
|
||||
int qc_ssl_provide_all_quic_data(struct quic_conn *qc, struct ssl_sock_ctx *ctx);
|
||||
|
||||
static inline void qc_free_ssl_sock_ctx(struct ssl_sock_ctx **ctx)
|
||||
{
|
||||
|
@ -222,6 +222,8 @@ struct quic_enc_level {
|
||||
struct eb_root pkts;
|
||||
/* List of QUIC packets with protected header. */
|
||||
struct list pqpkts;
|
||||
/* List of crypto frames received in order. */
|
||||
struct list crypto_frms;
|
||||
} rx;
|
||||
|
||||
/* TX part */
|
||||
|
@ -898,12 +898,18 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
|
||||
struct quic_conn *qc = context;
|
||||
struct buffer *buf = NULL;
|
||||
int st;
|
||||
struct tasklet *tl = (struct tasklet *)t;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
|
||||
|
||||
st = qc->state;
|
||||
TRACE_PROTO("connection state", QUIC_EV_CONN_IO_CB, qc, &st);
|
||||
|
||||
if (HA_ATOMIC_LOAD(&tl->state) & TASK_HEAVY) {
|
||||
HA_ATOMIC_AND(&tl->state, ~TASK_HEAVY);
|
||||
qc_ssl_provide_all_quic_data(qc, qc->xprt_ctx);
|
||||
}
|
||||
|
||||
/* Retranmissions */
|
||||
if (qc->flags & QUIC_FL_CONN_RETRANS_NEEDED) {
|
||||
TRACE_DEVEL("retransmission needed", QUIC_EV_CONN_PHPKTS, qc);
|
||||
@ -918,6 +924,11 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
|
||||
if (!qc_treat_rx_pkts(qc))
|
||||
goto out;
|
||||
|
||||
if (HA_ATOMIC_LOAD(&tl->state) & TASK_HEAVY) {
|
||||
tasklet_wakeup(tl);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (qc->flags & QUIC_FL_CONN_TO_KILL) {
|
||||
TRACE_DEVEL("connection to be killed", QUIC_EV_CONN_PHPKTS, qc);
|
||||
goto out;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <haproxy/trace.h>
|
||||
|
||||
DECLARE_POOL(pool_head_quic_frame, "quic_frame", sizeof(struct quic_frame));
|
||||
DECLARE_POOL(pool_head_qf_crypto, "qf_crypto", sizeof(struct qf_crypto));
|
||||
|
||||
const char *quic_frame_type_string(enum quic_frame_type ft)
|
||||
{
|
||||
|
@ -829,13 +829,22 @@ static int qc_handle_crypto_frm(struct quic_conn *qc,
|
||||
}
|
||||
|
||||
if (crypto_frm->offset == cstream->rx.offset && ncb_is_empty(ncbuf)) {
|
||||
if (!qc_ssl_provide_quic_data(&qel->cstream->rx.ncbuf, qel->level,
|
||||
qc->xprt_ctx, crypto_frm->data, crypto_frm->len)) {
|
||||
// trace already emitted by function above
|
||||
struct qf_crypto *qf_crypto;
|
||||
|
||||
qf_crypto = pool_alloc(pool_head_qf_crypto);
|
||||
if (!qf_crypto) {
|
||||
TRACE_ERROR("CRYPTO frame allocation failed", QUIC_EV_CONN_PRSHPKT, qc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
qf_crypto->offset = crypto_frm->offset;
|
||||
qf_crypto->len = crypto_frm->len;
|
||||
qf_crypto->data = crypto_frm->data;
|
||||
qf_crypto->qel = qel;
|
||||
LIST_APPEND(&qel->rx.crypto_frms, &qf_crypto->list);
|
||||
|
||||
cstream->rx.offset += crypto_frm->len;
|
||||
HA_ATOMIC_OR(&qc->wait_event.tasklet->state, TASK_HEAVY);
|
||||
TRACE_DEVEL("increment crypto level offset", QUIC_EV_CONN_PHPKTS, qc, qel);
|
||||
goto done;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <haproxy/ncbuf.h>
|
||||
#include <haproxy/proxy.h>
|
||||
#include <haproxy/quic_conn.h>
|
||||
#include <haproxy/quic_rx.h>
|
||||
#include <haproxy/quic_sock.h>
|
||||
#include <haproxy/quic_ssl.h>
|
||||
#include <haproxy/quic_tls.h>
|
||||
@ -633,6 +634,60 @@ int qc_ssl_provide_quic_data(struct ncbuf *ncbuf,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Provide all the stored in order CRYPTO data received from the peer to the TLS.
|
||||
* Return 1 if succeeded, 0 if not.
|
||||
*/
|
||||
int qc_ssl_provide_all_quic_data(struct quic_conn *qc, struct ssl_sock_ctx *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
struct quic_enc_level *qel;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc);
|
||||
list_for_each_entry(qel, &qc->qel_list, list) {
|
||||
int ssl_ret;
|
||||
struct quic_cstream *cstream = qel->cstream;
|
||||
struct ncbuf *ncbuf;
|
||||
struct qf_crypto *qf_crypto, *qf_back;
|
||||
|
||||
if (!qel->cstream) {
|
||||
TRACE_DEVEL("no cstream", QUIC_EV_CONN_PHPKTS, qc, qel);
|
||||
continue;
|
||||
}
|
||||
|
||||
ssl_ret = 1;
|
||||
ncbuf = &cstream->rx.ncbuf;
|
||||
list_for_each_entry_safe(qf_crypto, qf_back, &qel->rx.crypto_frms, list) {
|
||||
|
||||
ssl_ret = qc_ssl_provide_quic_data(ncbuf, qel->level, ctx,
|
||||
qf_crypto->data, qf_crypto->len);
|
||||
/* Free this frame asap */
|
||||
LIST_DELETE(&qf_crypto->list);
|
||||
pool_free(pool_head_qf_crypto, qf_crypto);
|
||||
|
||||
if (!ssl_ret) {
|
||||
TRACE_DEVEL("null ssl_ret", QUIC_EV_CONN_PHPKTS, qc, qel);
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE_DEVEL("buffered crypto data were provided to TLS stack",
|
||||
QUIC_EV_CONN_PHPKTS, qc, qel);
|
||||
}
|
||||
|
||||
if (ncb_is_empty(ncbuf)) {
|
||||
TRACE_DEVEL("freeing crypto buf", QUIC_EV_CONN_PHPKTS, qc, qel);
|
||||
quic_free_ncbuf(ncbuf);
|
||||
}
|
||||
|
||||
if (!ssl_ret)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
leave:
|
||||
TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Try to allocate the <*ssl> SSL session object for <qc> QUIC connection
|
||||
* with <ssl_ctx> as SSL context inherited settings. Also set the transport
|
||||
* parameters of this session.
|
||||
|
@ -114,6 +114,7 @@ void quic_tls_secret_hexdump(struct buffer *buf,
|
||||
void quic_conn_enc_level_uninit(struct quic_conn *qc, struct quic_enc_level *qel)
|
||||
{
|
||||
int i;
|
||||
struct qf_crypto *qf_crypto, *qfback;
|
||||
|
||||
TRACE_ENTER(QUIC_EV_CONN_CLOSE, qc);
|
||||
|
||||
@ -123,6 +124,12 @@ void quic_conn_enc_level_uninit(struct quic_conn *qc, struct quic_enc_level *qel
|
||||
qel->tx.crypto.bufs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(qf_crypto, qfback, &qel->rx.crypto_frms, list) {
|
||||
LIST_DELETE(&qf_crypto->list);
|
||||
pool_free(pool_head_qf_crypto, qf_crypto);
|
||||
}
|
||||
|
||||
ha_free(&qel->tx.crypto.bufs);
|
||||
quic_cstream_free(qel->cstream);
|
||||
|
||||
@ -160,6 +167,7 @@ static int quic_conn_enc_level_init(struct quic_conn *qc,
|
||||
|
||||
qel->rx.pkts = EB_ROOT;
|
||||
LIST_INIT(&qel->rx.pqpkts);
|
||||
LIST_INIT(&qel->rx.crypto_frms);
|
||||
|
||||
/* Allocate only one buffer. */
|
||||
/* TODO: use a pool */
|
||||
|
Loading…
Reference in New Issue
Block a user