diff --git a/src/quic_conn.c b/src/quic_conn.c index 5233496e3a..8c7d5aaf32 100644 --- a/src/quic_conn.c +++ b/src/quic_conn.c @@ -1818,7 +1818,14 @@ int qc_set_tid_affinity(struct quic_conn *qc, uint new_tid, struct listener *new qc_detach_th_ctx_list(qc, 0); node = eb64_first(qc->cids); - BUG_ON(!node || eb64_next(node)); /* One and only one CID must be present before affinity rebind. */ + /* One and only one CID must be present before affinity rebind. + * + * This could be triggered fairly easily if tasklet is scheduled just + * before thread migration for post-handshake state to generate new + * CIDs. In this case, QUIC_FL_CONN_IO_TO_REQUEUE should be used + * instead of tasklet_wakeup(). + */ + BUG_ON(!node || eb64_next(node)); conn_id = eb64_entry(node, struct quic_connection_id, seq_num); /* At this point no connection was accounted for yet on this diff --git a/src/quic_sock.c b/src/quic_sock.c index 4d51ef6fde..5bd65c7064 100644 --- a/src/quic_sock.c +++ b/src/quic_sock.c @@ -999,18 +999,15 @@ void qc_want_recv(struct quic_conn *qc) struct quic_accept_queue *quic_accept_queues; /* Install on the queue ready to be accepted. The queue task is then woken - * up. If accept is already scheduled or done, nothing is done. + * up. */ void quic_accept_push_qc(struct quic_conn *qc) { struct quic_accept_queue *queue = &quic_accept_queues[tid]; struct li_per_thread *lthr = &qc->li->per_thr[ti->ltid]; - /* early return if accept is already in progress/done for this - * connection - */ - if (qc->flags & QUIC_FL_CONN_ACCEPT_REGISTERED) - return; + /* A connection must only be accepted once per instance. */ + BUG_ON(qc->flags & QUIC_FL_CONN_ACCEPT_REGISTERED); BUG_ON(MT_LIST_INLIST(&qc->accept_list)); HA_ATOMIC_INC(&qc->li->rx.quic_curr_accept); diff --git a/src/quic_ssl.c b/src/quic_ssl.c index 08c119f3e7..6684973399 100644 --- a/src/quic_ssl.c +++ b/src/quic_ssl.c @@ -593,8 +593,17 @@ int qc_ssl_provide_quic_data(struct ncbuf *ncbuf, if (qc_is_listener(ctx->qc)) { qc->flags |= QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS; qc->state = QUIC_HS_ST_CONFIRMED; - /* The connection is ready to be accepted. */ - quic_accept_push_qc(qc); + + if (!(qc->flags & QUIC_FL_CONN_ACCEPT_REGISTERED)) { + quic_accept_push_qc(qc); + } + else { + /* Connection already accepted if 0-RTT used. + * In this case, schedule quic-conn to ensure + * post-handshake frames are emitted. + */ + tasklet_wakeup(qc->wait_event.tasklet); + } BUG_ON(qc->li->rx.quic_curr_handshake == 0); HA_ATOMIC_DEC(&qc->li->rx.quic_curr_handshake); diff --git a/src/xprt_quic.c b/src/xprt_quic.c index eda113cfc0..b83b6340c4 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -140,6 +140,13 @@ static int qc_xprt_start(struct connection *conn, void *ctx) /* mux-quic can now be considered ready. */ qc->mux_state = QC_MUX_READY; + /* Schedule quic-conn to ensure post handshake frames are emitted. This + * is not done for 0-RTT as xprt->start happens before handshake + * completion. + */ + if (qc->flags & QUIC_FL_CONN_NEED_POST_HANDSHAKE_FRMS) + tasklet_wakeup(qc->wait_event.tasklet); + ret = 1; out: TRACE_LEAVE(QUIC_EV_CONN_NEW, qc);