diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index 28a8103a5..d84be9cf1 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -243,6 +243,7 @@ struct qcc_app_ops { /* unused 0x00000010 */ #define QC_CF_ERR_CONN 0x00000020 /* fatal error reported by transport layer */ #define QC_CF_WAIT_HS 0x00000040 /* MUX init before QUIC handshake completed (0-RTT) */ +#define QC_CF_QOS 0x00000080 /* This function is used to report flags in debugging tools. Please reflect * below any single-bit flag addition above in the same order via the diff --git a/include/haproxy/mux_quic.h b/include/haproxy/mux_quic.h index d0b7fac81..e805c40bb 100644 --- a/include/haproxy/mux_quic.h +++ b/include/haproxy/mux_quic.h @@ -17,6 +17,8 @@ _qcc_report_glitch(qcc, inc); \ }) +int qmux_is_quic(const struct qcc *qcc); + void qcc_set_error(struct qcc *qcc, int err, int app); int _qcc_report_glitch(struct qcc *qcc, int inc); int qcc_fctl_avail_streams(const struct qcc *qcc, int bidi); diff --git a/src/mux_quic.c b/src/mux_quic.c index 2db2e3320..e78cd550d 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -40,10 +40,16 @@ DECLARE_STATIC_TYPED_POOL(pool_head_qc_stream_rxbuf, "qc_stream_rxbuf", struct q static void qmux_ctrl_send(struct qc_stream_desc *, uint64_t data, uint64_t offset); static void qmux_ctrl_room(struct qc_stream_desc *, uint64_t room); +int qmux_is_quic(const struct qcc *qcc) +{ + return !(qcc->flags & QC_CF_QOS); +} + /* Returns true if pacing should be used for connection. */ static int qcc_is_pacing_active(const struct connection *conn) { - return quic_tune_conn_test(QUIC_TUNE_FB_TX_PACING, conn); + struct qcc *qcc = conn->ctx; + return qmux_is_quic(qcc) && quic_tune_conn_test(QUIC_TUNE_FB_TX_PACING, conn); } /* Free instance and its inner data storage attached to stream. */ @@ -194,17 +200,19 @@ static struct qcs *qcs_new(struct qcc *qcc, uint64_t id, enum qcs_type type) tot_time_reset(&qcs->timer.fctl); tot_time_start(&qcs->timer.base); - /* Allocate transport layer stream descriptor. Only needed for TX. */ - if (!quic_stream_is_uni(id) || !quic_stream_is_remote(qcc, id)) { - struct quic_conn *qc = qcc->conn->handle.qc; - qcs->stream = qc_stream_desc_new(id, type, qcs, qc); - if (!qcs->stream) { - TRACE_ERROR("qc_stream_desc alloc failure", QMUX_EV_QCS_NEW, qcc->conn, qcs); - goto err; - } + if (qmux_is_quic(qcc)) { + /* Allocate transport layer stream descriptor. Only needed for TX. */ + if (!quic_stream_is_uni(id) || !quic_stream_is_remote(qcc, id)) { + struct quic_conn *qc = qcc->conn->handle.qc; + qcs->stream = qc_stream_desc_new(id, type, qcs, qc); + if (!qcs->stream) { + TRACE_ERROR("qc_stream_desc alloc failure", QMUX_EV_QCS_NEW, qcc->conn, qcs); + goto err; + } - qc_stream_desc_sub_send(qcs->stream, qmux_ctrl_send); - qc_stream_desc_sub_room(qcs->stream, qmux_ctrl_room); + qc_stream_desc_sub_send(qcs->stream, qmux_ctrl_send); + qc_stream_desc_sub_room(qcs->stream, qmux_ctrl_room); + } } if (qcc->app_ops->attach && qcc->app_ops->attach(qcs, qcc->ctx)) { @@ -675,8 +683,13 @@ static void qmux_ctrl_send(struct qc_stream_desc *stream, uint64_t data, uint64_ /* Returns true if buffer window does not have room for a new buffer. */ static inline int qcc_bufwnd_full(const struct qcc *qcc) { - const struct quic_conn *qc = qcc->conn->handle.qc; - return qcc->tx.buf_in_flight >= qc->path->cwnd; + if (qmux_is_quic(qcc)) { + const struct quic_conn *qc = qcc->conn->handle.qc; + return qcc->tx.buf_in_flight >= qc->path->cwnd; + } + else { + return 0; + } } static void qmux_ctrl_room(struct qc_stream_desc *stream, uint64_t room) @@ -905,13 +918,15 @@ static struct qcs *qcc_init_stream_remote(struct qcc *qcc, uint64_t id) */ void qcs_send_metadata(struct qcs *qcs) { - /* Reserved for stream with Tx capability. */ - BUG_ON(!qcs->stream); - /* Cannot use if some data already transferred for this stream. */ - BUG_ON(qcs->stream->ack_offset || !eb_is_empty(&qcs->stream->buf_tree)); + if (qmux_is_quic(qcs->qcc)) { + /* Reserved for stream with Tx capability. */ + BUG_ON(!qcs->stream); + /* Cannot use if some data already transferred for this stream. */ + BUG_ON(qcs->stream->ack_offset || !eb_is_empty(&qcs->stream->buf_tree)); - qcs->flags |= QC_SF_TXBUB_OOB; - qc_stream_desc_sub_room(qcs->stream, NULL); + qcs->flags |= QC_SF_TXBUB_OOB; + qc_stream_desc_sub_room(qcs->stream, NULL); + } } /* Instantiate a streamdesc instance for stream. This is necessary to @@ -1589,8 +1604,10 @@ static void _qcc_send_stream(struct qcs *qcs, int urg) qcc_clear_frms(qcc); if (urg) { - /* qcc_emit_rs_ss() relies on reset/aborted streams in send_list front. */ - BUG_ON(!(qcs->flags & (QC_SF_TO_RESET|QC_SF_TO_STOP_SENDING|QC_SF_TXBUB_OOB))); + if (qmux_is_quic(qcc)) { + /* qcc_emit_rs_ss() relies on reset/aborted streams in send_list front. */ + BUG_ON(!(qcs->flags & (QC_SF_TO_RESET|QC_SF_TO_STOP_SENDING|QC_SF_TXBUB_OOB))); + } LIST_DEL_INIT(&qcs->el_send); LIST_INSERT(&qcc->send_list, &qcs->el_send); @@ -2745,7 +2762,7 @@ static int qcc_emit_rs_ss(struct qcc *qcc) list_for_each_entry_safe(qcs, qcs_tmp, &qcc->send_list, el_send) { /* Stream must not be present in send_list if it has nothing to send. */ BUG_ON(!(qcs->flags & (QC_SF_FIN_STREAM|QC_SF_TO_STOP_SENDING|QC_SF_TO_RESET)) && - (!qcs->stream || !qcs_prep_bytes(qcs))); + (qmux_is_quic(qcc) && (!qcs->stream || !qcs_prep_bytes(qcs)))); /* Interrupt looping for the first stream where no RS nor SS is * necessary and is not use for "metadata" transfer. These @@ -2840,7 +2857,7 @@ static int qcc_build_frms(struct qcc *qcc, struct list *qcs_failed) /* Streams with RS/SS must be handled via qcc_emit_rs_ss(). */ BUG_ON(qcs->flags & (QC_SF_TO_STOP_SENDING|QC_SF_TO_RESET)); /* Stream must not be present in send_list if it has nothing to send. */ - BUG_ON(!(qcs->flags & QC_SF_FIN_STREAM) && (!qcs->stream || !qcs_prep_bytes(qcs))); + BUG_ON(!(qcs->flags & QC_SF_FIN_STREAM) && (qmux_is_quic(qcc) && (!qcs->stream || !qcs_prep_bytes(qcs)))); /* Total sent bytes must not exceed connection window. */ BUG_ON(total > window_conn); @@ -3202,24 +3219,28 @@ static void qcc_shutdown(struct qcc *qcc) if (qcc->app_st >= QCC_APP_ST_SHUT) goto out; - TRACE_STATE("perform graceful shutdown", QMUX_EV_QCC_END, qcc->conn); - if (qcc->app_ops && qcc->app_ops->shutdown) { - qcc->app_ops->shutdown(qcc->ctx); - qcc_io_send(qcc); - } - else { - qcc->err = quic_err_transport(QC_ERR_NO_ERROR); + if (qmux_is_quic(qcc)) { + TRACE_STATE("perform graceful shutdown", QMUX_EV_QCC_END, qcc->conn); + if (qcc->app_ops && qcc->app_ops->shutdown) { + qcc->app_ops->shutdown(qcc->ctx); + qcc_io_send(qcc); + } + else { + qcc->err = quic_err_transport(QC_ERR_NO_ERROR); + } } - /* Register "no error" code at transport layer. Do not use - * quic_set_connection_close() as retransmission may be performed to - * finalized transfers. Do not overwrite quic-conn existing code if - * already set. - * - * TODO implement a wrapper function for this in quic-conn module - */ - if (!(qcc->conn->handle.qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) - qcc->conn->handle.qc->err = qcc->err; + if (qmux_is_quic(qcc)) { + /* Register "no error" code at transport layer. Do not use + * quic_set_connection_close() as retransmission may be performed to + * finalized transfers. Do not overwrite quic-conn existing code if + * already set. + * + * TODO implement a wrapper function for this in quic-conn module + */ + if (!(qcc->conn->handle.qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) + qcc->conn->handle.qc->err = qcc->err; + } /* A connection is not reusable if app layer is closed. */ if (qcc->flags & QC_CF_IS_BACK) @@ -3341,7 +3362,7 @@ static void qcc_release(struct qcc *qcc) qcs_free(qcs); } - if (conn) { + if (qmux_is_quic(qcc) && conn) { qc = conn->handle.qc; /* unsubscribe from all remaining qc_stream_desc */ diff --git a/src/qmux_trace.c b/src/qmux_trace.c index 6e879bb69..01f3d4507 100644 --- a/src/qmux_trace.c +++ b/src/qmux_trace.c @@ -143,18 +143,19 @@ static char *qcc_app_st_to_str(const enum qcc_app_st st) void qmux_dump_qcc_info(struct buffer *msg, const struct qcc *qcc) { - const struct quic_conn *qc = qcc->conn->handle.qc; + const struct quic_conn *qc = qmux_is_quic(qcc) ? qcc->conn->handle.qc : NULL; chunk_appendf(msg, " qcc=%p(%c)", qcc, (qcc->flags & QC_CF_IS_BACK) ? 'B' : 'F'); - if (qcc->conn->handle.qc) + if (qc) chunk_appendf(msg, " qc=%p", qcc->conn->handle.qc); chunk_appendf(msg, " .st=%s .sc=%llu .hreq=%llu .flg=0x%04x", qcc_app_st_to_str(qcc->app_st), (ullong)qcc->nb_sc, (ullong)qcc->nb_hreq, qcc->flags); - chunk_appendf(msg, " .tx=%llu %llu/%llu bwnd=%llu/%llu", - (ullong)qcc->tx.fc.off_soft, (ullong)qcc->tx.fc.off_real, (ullong)qcc->tx.fc.limit, - (ullong)qcc->tx.buf_in_flight, (ullong)qc->path->cwnd); + chunk_appendf(msg, " .tx=%llu %llu/%llu", + (ullong)qcc->tx.fc.off_soft, (ullong)qcc->tx.fc.off_real, (ullong)qcc->tx.fc.limit); + if (qc) + chunk_appendf(msg, " bwnd=%llu/%llu", (ullong)qcc->tx.buf_in_flight, (ullong)qc->path->cwnd); } void qmux_dump_qcs_info(struct buffer *msg, const struct qcs *qcs)