MINOR: mux-quic: protect QUIC specific bits

This commit is contained in:
Amaury Denoyelle 2025-02-19 14:50:12 +01:00
parent 36946bb9c3
commit b741247396
4 changed files with 70 additions and 45 deletions

View File

@ -237,6 +237,7 @@ struct qcc_app_ops {
/* unused 0x00000010 */ /* unused 0x00000010 */
#define QC_CF_ERR_CONN 0x00000020 /* fatal error reported by transport layer */ #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_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 /* 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 * below any single-bit flag addition above in the same order via the

View File

@ -17,6 +17,8 @@
_qcc_report_glitch(qcc, inc); \ _qcc_report_glitch(qcc, inc); \
}) })
int qmux_is_quic(const struct qcc *qcc);
void qcc_set_error(struct qcc *qcc, int err, int app); void qcc_set_error(struct qcc *qcc, int err, int app);
int _qcc_report_glitch(struct qcc *qcc, int inc); int _qcc_report_glitch(struct qcc *qcc, int inc);
struct qcs *qcc_init_stream_local(struct qcc *qcc, int bidi); struct qcs *qcc_init_stream_local(struct qcc *qcc, int bidi);

View File

@ -39,10 +39,16 @@ DECLARE_STATIC_POOL(pool_head_qc_stream_rxbuf, "qc_stream_rxbuf", sizeof(struct
static void qmux_ctrl_send(struct qc_stream_desc *, uint64_t data, uint64_t offset); 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); 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 <conn> connection. */ /* Returns true if pacing should be used for <conn> connection. */
static int qcc_is_pacing_active(const struct connection *conn) static int qcc_is_pacing_active(const struct connection *conn)
{ {
return !(quic_tune.options & QUIC_TUNE_NO_PACING); struct qcc *qcc = conn->ctx;
return qmux_is_quic(qcc) && !(quic_tune.options & QUIC_TUNE_NO_PACING);
} }
/* Free <rxbuf> instance and its inner data storage attached to <qcs> stream. */ /* Free <rxbuf> instance and its inner data storage attached to <qcs> stream. */
@ -198,17 +204,19 @@ static struct qcs *qcs_new(struct qcc *qcc, uint64_t id, enum qcs_type type)
if (!(global.tune.no_zero_copy_fwd & NO_ZERO_COPY_FWD_QUIC_SND)) if (!(global.tune.no_zero_copy_fwd & NO_ZERO_COPY_FWD_QUIC_SND))
se_fl_set(qcs->sd, SE_FL_MAY_FASTFWD_CONS); se_fl_set(qcs->sd, SE_FL_MAY_FASTFWD_CONS);
/* Allocate transport layer stream descriptor. Only needed for TX. */ if (qmux_is_quic(qcc)) {
if (!quic_stream_is_uni(id) || !quic_stream_is_remote(qcc, id)) { /* Allocate transport layer stream descriptor. Only needed for TX. */
struct quic_conn *qc = qcc->conn->handle.qc; if (!quic_stream_is_uni(id) || !quic_stream_is_remote(qcc, id)) {
qcs->stream = qc_stream_desc_new(id, type, qcs, qc); struct quic_conn *qc = qcc->conn->handle.qc;
if (!qcs->stream) { qcs->stream = qc_stream_desc_new(id, type, qcs, qc);
TRACE_ERROR("qc_stream_desc alloc failure", QMUX_EV_QCS_NEW, qcc->conn, qcs); if (!qcs->stream) {
goto err; 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_send(qcs->stream, qmux_ctrl_send);
qc_stream_desc_sub_room(qcs->stream, qmux_ctrl_room); qc_stream_desc_sub_room(qcs->stream, qmux_ctrl_room);
}
} }
if (qcc->app_ops->attach && qcc->app_ops->attach(qcs, qcc->ctx)) { if (qcc->app_ops->attach && qcc->app_ops->attach(qcs, qcc->ctx)) {
@ -681,8 +689,13 @@ static void qmux_ctrl_send(struct qc_stream_desc *stream, uint64_t data, uint64_
/* Returns true if <qcc> buffer window does not have room for a new buffer. */ /* Returns true if <qcc> buffer window does not have room for a new buffer. */
static inline int qcc_bufwnd_full(const struct qcc *qcc) static inline int qcc_bufwnd_full(const struct qcc *qcc)
{ {
const struct quic_conn *qc = qcc->conn->handle.qc; if (qmux_is_quic(qcc)) {
return qcc->tx.buf_in_flight >= qc->path->cwnd; 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) static void qmux_ctrl_room(struct qc_stream_desc *stream, uint64_t room)
@ -895,13 +908,15 @@ static struct qcs *qcc_init_stream_remote(struct qcc *qcc, uint64_t id)
*/ */
void qcs_send_metadata(struct qcs *qcs) void qcs_send_metadata(struct qcs *qcs)
{ {
/* Reserved for stream with Tx capability. */ if (qmux_is_quic(qcs->qcc)) {
BUG_ON(!qcs->stream); /* Reserved for stream with Tx capability. */
/* Cannot use if some data already transferred for this stream. */ BUG_ON(!qcs->stream);
BUG_ON(qcs->stream->ack_offset || !eb_is_empty(&qcs->stream->buf_tree)); /* 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; qcs->flags |= QC_SF_TXBUB_OOB;
qc_stream_desc_sub_room(qcs->stream, NULL); qc_stream_desc_sub_room(qcs->stream, NULL);
}
} }
/* Instantiate a streamdesc instance for <qcs> stream. This is necessary to /* Instantiate a streamdesc instance for <qcs> stream. This is necessary to
@ -1529,8 +1544,10 @@ static void _qcc_send_stream(struct qcs *qcs, int urg)
qcc_clear_frms(qcc); qcc_clear_frms(qcc);
if (urg) { if (urg) {
/* qcc_emit_rs_ss() relies on reset/aborted streams in send_list front. */ if (qmux_is_quic(qcc)) {
BUG_ON(!(qcs->flags & (QC_SF_TO_RESET|QC_SF_TO_STOP_SENDING|QC_SF_TXBUB_OOB))); /* 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_DEL_INIT(&qcs->el_send);
LIST_INSERT(&qcc->send_list, &qcs->el_send); LIST_INSERT(&qcc->send_list, &qcs->el_send);
@ -2571,7 +2588,7 @@ static int qcc_emit_rs_ss(struct qcc *qcc)
list_for_each_entry_safe(qcs, qcs_tmp, &qcc->send_list, el_send) { 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. */ /* 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)) && 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 /* Interrupt looping for the first stream where no RS nor SS is
* necessary and is not use for "metadata" transfer. These * necessary and is not use for "metadata" transfer. These
@ -2666,7 +2683,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(). */ /* 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)); 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. */ /* 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. */ /* Total sent bytes must not exceed connection window. */
BUG_ON(total > window_conn); BUG_ON(total > window_conn);
@ -3000,24 +3017,28 @@ static void qcc_shutdown(struct qcc *qcc)
if (qcc->app_st >= QCC_APP_ST_SHUT) if (qcc->app_st >= QCC_APP_ST_SHUT)
goto out; goto out;
TRACE_STATE("perform graceful shutdown", QMUX_EV_QCC_END, qcc->conn); if (qmux_is_quic(qcc)) {
if (qcc->app_ops && qcc->app_ops->shutdown) { TRACE_STATE("perform graceful shutdown", QMUX_EV_QCC_END, qcc->conn);
qcc->app_ops->shutdown(qcc->ctx); if (qcc->app_ops && qcc->app_ops->shutdown) {
qcc_io_send(qcc); qcc->app_ops->shutdown(qcc->ctx);
} qcc_io_send(qcc);
else { }
qcc->err = quic_err_transport(QC_ERR_NO_ERROR); else {
qcc->err = quic_err_transport(QC_ERR_NO_ERROR);
}
} }
/* Register "no error" code at transport layer. Do not use if (qmux_is_quic(qcc)) {
* quic_set_connection_close() as retransmission may be performed to /* Register "no error" code at transport layer. Do not use
* finalized transfers. Do not overwrite quic-conn existing code if * quic_set_connection_close() as retransmission may be performed to
* already set. * finalized transfers. Do not overwrite quic-conn existing code if
* * already set.
* TODO implement a wrapper function for this in quic-conn module *
*/ * 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 (!(qcc->conn->handle.qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE))
qcc->conn->handle.qc->err = qcc->err;
}
out: out:
qcc->app_st = QCC_APP_ST_SHUT; qcc->app_st = QCC_APP_ST_SHUT;
@ -3137,7 +3158,7 @@ static void qcc_release(struct qcc *qcc)
} }
/* unsubscribe from all remaining qc_stream_desc */ /* unsubscribe from all remaining qc_stream_desc */
if (conn) { if (qmux_is_quic(qcc) && conn) {
qc = conn->handle.qc; qc = conn->handle.qc;
node = eb64_first(&qc->streams_by_id); node = eb64_first(&qc->streams_by_id);
while (node) { while (node) {

View File

@ -142,18 +142,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) 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(F)", qcc); chunk_appendf(msg, " qcc=%p(F)", qcc);
if (qcc->conn->handle.qc) if (qc)
chunk_appendf(msg, " qc=%p", qcc->conn->handle.qc); chunk_appendf(msg, " qc=%p", qcc->conn->handle.qc);
chunk_appendf(msg, " .st=%s .sc=%llu .hreq=%llu .flg=0x%04x", chunk_appendf(msg, " .st=%s .sc=%llu .hreq=%llu .flg=0x%04x",
qcc_app_st_to_str(qcc->app_st), (ullong)qcc->nb_sc, qcc_app_st_to_str(qcc->app_st), (ullong)qcc->nb_sc,
(ullong)qcc->nb_hreq, qcc->flags); (ullong)qcc->nb_hreq, qcc->flags);
chunk_appendf(msg, " .tx=%llu %llu/%llu bwnd=%llu/%llu", chunk_appendf(msg, " .tx=%llu %llu/%llu",
(ullong)qcc->tx.fc.off_soft, (ullong)qcc->tx.fc.off_real, (ullong)qcc->tx.fc.limit, (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); 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) void qmux_dump_qcs_info(struct buffer *msg, const struct qcs *qcs)