]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: Post handshake I/O callback switching
authorFrédéric Lécaille <flecaille@haproxy.com>
Fri, 18 Feb 2022 16:13:45 +0000 (17:13 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 1 Mar 2022 15:22:35 +0000 (16:22 +0100)
Implement a simple task quic_conn_app_io_cb() to be used after the handshakes
have completed.

include/haproxy/xprt_quic-t.h
src/xprt_quic.c

index 773c2fe9668002c046bbf4ce01ae644b3209bef6..ef40851112c57d8e3a4fd2f11b3cb9b23a6c602e 100644 (file)
@@ -196,7 +196,7 @@ enum quic_pkt_type {
 #define           QUIC_EV_CONN_HPKT      (1ULL << 9)
 #define           QUIC_EV_CONN_PAPKT     (1ULL << 10)
 #define           QUIC_EV_CONN_PAPKTS    (1ULL << 11)
-#define           QUIC_EV_CONN_HDSHK     (1ULL << 12)
+#define           QUIC_EV_CONN_IO_CB     (1ULL << 12)
 #define           QUIC_EV_CONN_RMHP      (1ULL << 13)
 #define           QUIC_EV_CONN_PRSHPKT   (1ULL << 14)
 #define           QUIC_EV_CONN_PRSAPKT   (1ULL << 15)
index e2252865342fc8d78d4383df5c9940dc00a33e1e..9e31a75bbe22f762b347db73eaa1b0940cd08f15 100644 (file)
@@ -93,7 +93,7 @@ static const struct trace_event quic_trace_events[] = {
        { .mask = QUIC_EV_CONN_HPKT,     .name = "hdshk_pkt",        .desc = "handhshake packet building" },
        { .mask = QUIC_EV_CONN_PAPKT,    .name = "phdshk_apkt",      .desc = "post handhshake application packet preparation" },
        { .mask = QUIC_EV_CONN_PAPKTS,   .name = "phdshk_apkts",     .desc = "post handhshake application packets preparation" },
-       { .mask = QUIC_EV_CONN_HDSHK,    .name = "hdshk",            .desc = "SSL handhshake processing" },
+       { .mask = QUIC_EV_CONN_IO_CB,    .name = "qc_io_cb",         .desc = "QUIC conn. I/O processin" },
        { .mask = QUIC_EV_CONN_RMHP,     .name = "rm_hp",            .desc = "Remove header protection" },
        { .mask = QUIC_EV_CONN_PRSHPKT,  .name = "parse_hpkt",       .desc = "parse handshake packet" },
        { .mask = QUIC_EV_CONN_PRSAPKT,  .name = "parse_apkt",       .desc = "parse application packet" },
@@ -173,6 +173,7 @@ static struct quic_tx_packet *qc_build_pkt(unsigned char **pos, const unsigned c
                                            struct quic_enc_level *qel,
                                            struct quic_conn *qc, size_t dglen, int pkt_type,
                                            int padding, int ack, int probe, int cc, int *err);
+static struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int state);
 
 /* Only for debug purpose */
 struct enc_debug_info {
@@ -319,7 +320,7 @@ static void quic_trace(enum trace_level level, uint64_t mask, const struct trace
                        }
                }
 
-               if (mask & QUIC_EV_CONN_HDSHK) {
+               if (mask & QUIC_EV_CONN_IO_CB) {
                        const enum quic_handshake_state *state = a2;
                        const int *err = a3;
 
@@ -1904,18 +1905,20 @@ static inline int qc_provide_cdata(struct quic_enc_level *el,
                        ssl_err = SSL_get_error(ctx->ssl, ssl_err);
                        if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
                                TRACE_PROTO("SSL handshake",
-                                           QUIC_EV_CONN_HDSHK, qc, &state, &ssl_err);
+                                           QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err);
                                goto out;
                        }
 
                        TRACE_DEVEL("SSL handshake error",
-                                   QUIC_EV_CONN_HDSHK, qc, &state, &ssl_err);
+                                   QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err);
                        qc_ssl_dump_errors(ctx->conn);
                        ERR_clear_error();
                        goto err;
                }
 
-               TRACE_PROTO("SSL handshake OK", QUIC_EV_CONN_HDSHK, qc, &state);
+               TRACE_PROTO("SSL handshake OK", QUIC_EV_CONN_IO_CB, qc, &state);
+               /* I/O callback switch */
+               ctx->wait_event.tasklet->process = quic_conn_app_io_cb;
                if (qc_is_listener(ctx->qc)) {
                        HA_ATOMIC_STORE(&qc->state, QUIC_HS_ST_CONFIRMED);
                        /* The connection is ready to be accepted. */
@@ -1930,17 +1933,17 @@ static inline int qc_provide_cdata(struct quic_enc_level *el,
                        ssl_err = SSL_get_error(ctx->ssl, ssl_err);
                        if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
                                TRACE_DEVEL("SSL post handshake",
-                                           QUIC_EV_CONN_HDSHK, qc, &state, &ssl_err);
+                                           QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err);
                                goto out;
                        }
 
                        TRACE_DEVEL("SSL post handshake error",
-                                   QUIC_EV_CONN_HDSHK, qc, &state, &ssl_err);
+                                   QUIC_EV_CONN_IO_CB, qc, &state, &ssl_err);
                        goto err;
                }
 
                TRACE_PROTO("SSL post handshake succeeded",
-                           QUIC_EV_CONN_HDSHK, qc, &state);
+                           QUIC_EV_CONN_IO_CB, qc, &state);
        }
 
  out:
@@ -3155,6 +3158,68 @@ static int qc_qel_may_rm_hp(struct quic_conn *qc, struct quic_enc_level *qel)
        return 1;
 }
 
+/* Sends application level packets from <qc> QUIC connection */
+static int qc_send_app_pkts(struct quic_conn *qc)
+{
+       int ret;
+       struct qring *qr;
+
+       qr = MT_LIST_POP(qc->tx.qring_list, typeof(qr), mt_list);
+       if (!qr)
+               /* Never happens */
+               return 1;
+
+       ret = qc_prep_pkts(qc, qr, QUIC_TLS_ENC_LEVEL_APP, QUIC_TLS_ENC_LEVEL_NONE);
+       if (ret == -1)
+               goto err;
+       else if (ret == 0)
+               goto out;
+
+       if (!qc_send_ppkts(qr, qc->xprt_ctx))
+               goto err;
+
+ out:
+       MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
+       return 1;
+
+ err:
+       MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
+       TRACE_DEVEL("leaving in error", QUIC_EV_CONN_IO_CB, qc);
+       return 0;
+}
+
+/* QUIC connection packet handler task (post handshake) */
+static struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int state)
+{
+       struct ssl_sock_ctx *ctx;
+       struct quic_conn *qc;
+       struct quic_enc_level *qel;
+       int st;
+
+
+       ctx = context;
+       qc = ctx->qc;
+       qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP];
+       st = HA_ATOMIC_LOAD(&qc->state);
+
+       TRACE_PROTO("state", QUIC_EV_CONN_IO_CB, qc, &st);
+
+       if (!MT_LIST_ISEMPTY(&qel->rx.pqpkts) && qc_qel_may_rm_hp(qc, qel))
+               qc_rm_hp_pkts(qc, qel);
+
+       if (!qc_treat_rx_pkts(qel, NULL, ctx, 0))
+               goto err;
+
+       if (!qc_send_app_pkts(qc))
+               goto err;
+
+       return t;
+
+ err:
+       TRACE_DEVEL("leaving in error", QUIC_EV_CONN_IO_CB, qc, &st);
+       return t;
+}
+
 /* QUIC connection packet handler task. */
 struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
 {
@@ -3168,10 +3233,10 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
 
        ctx = context;
        qc = ctx->qc;
-       TRACE_ENTER(QUIC_EV_CONN_HDSHK, qc);
+       TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
        qr = NULL;
        st = HA_ATOMIC_LOAD(&qc->state);
-       TRACE_PROTO("state", QUIC_EV_CONN_HDSHK, qc, &st);
+       TRACE_PROTO("state", QUIC_EV_CONN_IO_CB, qc, &st);
        if (HA_ATOMIC_LOAD(&qc->flags) & QUIC_FL_CONN_IO_CB_WAKEUP) {
                HA_ATOMIC_BTR(&qc->flags, QUIC_FL_CONN_IO_CB_WAKEUP_BIT);
                /* The I/O handler has been woken up by the dgram listener
@@ -3267,13 +3332,13 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
        }
 
        MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
-       TRACE_LEAVE(QUIC_EV_CONN_HDSHK, qc, &st);
+       TRACE_LEAVE(QUIC_EV_CONN_IO_CB, qc, &st);
        return t;
 
  err:
        if (qr)
                MT_LIST_APPEND(qc->tx.qring_list, &qr->mt_list);
-       TRACE_DEVEL("leaving in error", QUIC_EV_CONN_HDSHK, qc, &st, &ssl_err);
+       TRACE_DEVEL("leaving in error", QUIC_EV_CONN_IO_CB, qc, &st, &ssl_err);
        return t;
 }