mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-28 22:31:06 +01:00
MINOR: mux-quic: support max bidi streams value set by the peer
Implement support for MAX_STREAMS frame. On frontend, this was mostly useless as haproxy would never initiate new bidirectional streams. However, this becomes necessary to control stream flow-control when using QUIC as a client on the backend side. Parsing of MAX_STREAMS is implemented via new qcc_recv_max_streams(). This allows to update <ms_uni>/<ms_bidi> QCC fields. This patch is necessary to achieve QUIC backend connection reuse.
This commit is contained in:
parent
805a070ab9
commit
06cab99a0e
@ -67,6 +67,7 @@ struct qcc {
|
||||
/* flow-control fields set by the peer which we must respect. */
|
||||
struct {
|
||||
uint64_t ms_uni; /* max sub-ID of uni stream allowed by the peer */
|
||||
uint64_t ms_bidi; /* max sub-ID of bidi stream allowed by the peer */
|
||||
|
||||
uint64_t md; /* connection flow control limit updated on MAX_DATA frames reception */
|
||||
uint64_t msd_bidi_l; /* initial max-stream-data from peer on local bidi streams */
|
||||
|
||||
@ -44,6 +44,7 @@ int qcc_recv(struct qcc *qcc, uint64_t id, uint64_t len, uint64_t offset,
|
||||
char fin, char *data);
|
||||
int qcc_recv_max_data(struct qcc *qcc, uint64_t max);
|
||||
int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max);
|
||||
int qcc_recv_max_streams(struct qcc *qcc, uint64_t max, int bidi);
|
||||
int qcc_recv_reset_stream(struct qcc *qcc, uint64_t id, uint64_t err, uint64_t final_size);
|
||||
int qcc_recv_stop_sending(struct qcc *qcc, uint64_t id, uint64_t err);
|
||||
|
||||
|
||||
@ -789,8 +789,9 @@ int _qcc_report_glitch(struct qcc *qcc, int inc)
|
||||
int qcc_fctl_avail_streams(const struct qcc *qcc, int bidi)
|
||||
{
|
||||
if (bidi) {
|
||||
/* TODO */
|
||||
return 0;
|
||||
const uint64_t next = qcc->next_bidi_l / 4;
|
||||
BUG_ON(qcc->rfctl.ms_bidi < next);
|
||||
return qcc->rfctl.ms_bidi - next;
|
||||
}
|
||||
else {
|
||||
const uint64_t next = qcc->next_uni_l / 4;
|
||||
@ -2032,6 +2033,57 @@ int qcc_recv_max_stream_data(struct qcc *qcc, uint64_t id, uint64_t max)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Handle a MAX_STREAMS frame. <max> must contains the cumulative number of
|
||||
* streams that can be opened. <bidi> is a boolean set if this refers to
|
||||
* bidirectional streams.
|
||||
*
|
||||
* Returns 0 on success else non-zero. On error, the received frame should not
|
||||
* be acknowledged.
|
||||
*/
|
||||
int qcc_recv_max_streams(struct qcc *qcc, uint64_t max, int bidi)
|
||||
{
|
||||
TRACE_ENTER(QMUX_EV_QCC_RECV, qcc->conn);
|
||||
|
||||
if (qcc->flags & QC_CF_ERRL) {
|
||||
TRACE_DATA("connection on error", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* RFC 9000 19.11. MAX_STREAMS Frames
|
||||
*
|
||||
* This value cannot exceed 2^60, as it is not possible to
|
||||
* encode stream IDs larger than 2^62-1. Receipt of a frame that
|
||||
* permits opening of a stream larger than this limit MUST be treated
|
||||
* as a connection error of type FRAME_ENCODING_ERROR.
|
||||
*/
|
||||
if (max > QUIC_VARINT_8_BYTE_MAX) {
|
||||
TRACE_ERROR("invalid MAX_STREAMS value", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
qcc_set_error(qcc, QC_ERR_FRAME_ENCODING_ERROR, 0);
|
||||
goto err;
|
||||
}
|
||||
|
||||
TRACE_PROTO("receiving MAX_STREAMS", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
if (bidi) {
|
||||
if (max > qcc->rfctl.ms_bidi) {
|
||||
TRACE_DATA("increase remote max-streams-bidi", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
qcc->rfctl.ms_bidi = max;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* TODO no extra unidirectional streams open after connection
|
||||
* startup, so uni MAX_STREAMS flow-control is not necessary
|
||||
* for now.
|
||||
*/
|
||||
}
|
||||
|
||||
TRACE_LEAVE(QMUX_EV_QCC_RECV, qcc->conn);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
TRACE_DEVEL("leaving on error", QMUX_EV_QCC_RECV, qcc->conn);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Handle a new RESET_STREAM frame from stream ID <id> with error code <err>
|
||||
* and final stream size <final_size>.
|
||||
*
|
||||
@ -3452,6 +3504,7 @@ static int qmux_init(struct connection *conn, struct proxy *prx,
|
||||
rparams = &conn->handle.qc->tx.params;
|
||||
qfctl_init(&qcc->tx.fc, rparams->initial_max_data);
|
||||
qcc->rfctl.ms_uni = rparams->initial_max_streams_uni;
|
||||
qcc->rfctl.ms_bidi = rparams->initial_max_streams_bidi;
|
||||
qcc->rfctl.msd_bidi_l = rparams->initial_max_stream_data_bidi_local;
|
||||
qcc->rfctl.msd_bidi_r = rparams->initial_max_stream_data_bidi_remote;
|
||||
qcc->rfctl.msd_uni_l = rparams->initial_max_stream_data_uni;
|
||||
|
||||
@ -1011,6 +1011,24 @@ static int qc_parse_pkt_frms(struct quic_conn *qc, struct quic_rx_packet *pkt,
|
||||
break;
|
||||
case QUIC_FT_MAX_STREAMS_BIDI:
|
||||
case QUIC_FT_MAX_STREAMS_UNI:
|
||||
if (qc->mux_state == QC_MUX_READY) {
|
||||
int bidi;
|
||||
struct qf_max_streams *ms_frm;
|
||||
|
||||
if (frm->type == QUIC_FT_MAX_STREAMS_BIDI) {
|
||||
bidi = 1;
|
||||
ms_frm = &frm->max_streams_bidi;
|
||||
}
|
||||
else {
|
||||
bidi = 0;
|
||||
ms_frm = &frm->max_streams_uni;
|
||||
}
|
||||
|
||||
if (qcc_recv_max_streams(qc->qcc, ms_frm->max_streams, bidi)) {
|
||||
TRACE_ERROR("qcc_recv_max_streams() failed", QUIC_EV_CONN_PRSHPKT, qc);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case QUIC_FT_DATA_BLOCKED:
|
||||
qc->cntrs.data_blocked++;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user