From: Amaury Denoyelle Date: Fri, 20 May 2022 13:05:07 +0000 (+0200) Subject: MINOR: mux-quic: emit FLOW_CONTROL_ERROR X-Git-Tag: v2.6-dev11~26 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d46b0f52aef145d81379046d11bb30ffcc855884;p=thirdparty%2Fhaproxy.git MINOR: mux-quic: emit FLOW_CONTROL_ERROR Send a CONNECTION_CLOSE if the peer emits more data than authorized by our flow-control. This is implemented for both stream and connection level. Fields have been added in qcc/qcs structures to differentiate received offsets for limit enforcing with consumed offsets for sending of MAX_DATA/MAX_STREAM_DATA frames. --- diff --git a/include/haproxy/mux_quic-t.h b/include/haproxy/mux_quic-t.h index b2d0aad039..903e326234 100644 --- a/include/haproxy/mux_quic-t.h +++ b/include/haproxy/mux_quic-t.h @@ -60,7 +60,8 @@ struct qcc { uint64_t md; /* current max-data allowed for the peer */ uint64_t md_init; /* initial max-data */ - uint64_t sent_offsets; /* sum of all offsets received */ + uint64_t offsets_recv; /* sum of offsets received */ + uint64_t offsets_consume; /* sum of offsets consumed */ } lfctl; /* flow-control fields set by the peer which we must respect. */ @@ -108,6 +109,7 @@ struct qcs { struct { uint64_t offset; /* absolute current base offset of ncbuf */ + uint64_t offset_max; /* maximum absolute offset received */ struct ncbuf ncbuf; /* receive buffer - can handle out-of-order offset frames */ struct buffer app_buf; /* receive buffer used by conn_stream layer */ uint64_t msd; /* current max-stream-data limit to enforce */ diff --git a/src/mux_quic.c b/src/mux_quic.c index 0e3e2c2e51..8485f818bb 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -165,7 +165,7 @@ struct qcs *qcs_new(struct qcc *qcc, uint64_t id, enum qcs_type type) qcs->rx.ncbuf = NCBUF_NULL; qcs->rx.app_buf = BUF_NULL; - qcs->rx.offset = 0; + qcs->rx.offset = qcs->rx.offset_max = 0; /* TODO use uni limit for unidirectional streams */ qcs->rx.msd = quic_stream_is_local(qcc, id) ? qcc->lfctl.msd_bidi_l : @@ -333,12 +333,12 @@ void qcs_consume(struct qcs *qcs, uint64_t bytes) tasklet_wakeup(qcc->wait_event.tasklet); } - qcc->lfctl.sent_offsets += bytes; - if (qcc->lfctl.md - qcc->lfctl.sent_offsets < qcc->lfctl.md_init / 2) { + qcc->lfctl.offsets_consume += bytes; + if (qcc->lfctl.md - qcc->lfctl.offsets_consume < qcc->lfctl.md_init / 2) { frm = pool_zalloc(pool_head_quic_frame); BUG_ON(!frm); /* TODO handle this properly */ - qcc->lfctl.md = qcc->lfctl.sent_offsets + qcc->lfctl.md_init; + qcc->lfctl.md = qcc->lfctl.offsets_consume + qcc->lfctl.md_init; LIST_INIT(&frm->reflist); frm->type = QUIC_FT_MAX_DATA; @@ -486,8 +486,25 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset, * Else send FINAL_SIZE_ERROR. */ - /* TODO initial max-stream-data overflow. Implement FLOW_CONTROL_ERROR emission. */ - BUG_ON(offset + len > qcs->rx.msd); + if (offset + len > qcs->rx.offset_max) { + uint64_t diff = offset + len - qcs->rx.offset_max; + qcs->rx.offset_max = offset + len; + qcc->lfctl.offsets_recv += diff; + + if (offset + len > qcs->rx.msd || + qcc->lfctl.offsets_recv > qcc->lfctl.md) { + /* RFC 9000 4.1. Data Flow Control + * + * A receiver MUST close the connection with an error + * of type FLOW_CONTROL_ERROR if the sender violates + * the advertised connection or stream data limits + */ + TRACE_DEVEL("leaving on flow control error", QMUX_EV_QCC_RECV|QMUX_EV_QCS_RECV, + qcc->conn, qcs); + qcc_emit_cc(qcc, QC_ERR_FLOW_CONTROL_ERROR); + return 1; + } + } if (!qc_get_ncbuf(qcs, &qcs->rx.ncbuf) || ncb_is_null(&qcs->rx.ncbuf)) { /* TODO should mark qcs as full */ @@ -1283,7 +1300,7 @@ static int qc_init(struct connection *conn, struct proxy *prx, qcc->lfctl.cl_bidi_r = 0; qcc->lfctl.md = qcc->lfctl.md_init = lparams->initial_max_data; - qcc->lfctl.sent_offsets = 0; + qcc->lfctl.offsets_recv = qcc->lfctl.offsets_consume = 0; rparams = &conn->handle.qc->tx.params; qcc->rfctl.md = rparams->initial_max_data;