mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-11-29 06:40:59 +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. */
|
/* flow-control fields set by the peer which we must respect. */
|
||||||
struct {
|
struct {
|
||||||
uint64_t ms_uni; /* max sub-ID of uni stream allowed by the peer */
|
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 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 */
|
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);
|
char fin, char *data);
|
||||||
int qcc_recv_max_data(struct qcc *qcc, uint64_t max);
|
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_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_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);
|
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)
|
int qcc_fctl_avail_streams(const struct qcc *qcc, int bidi)
|
||||||
{
|
{
|
||||||
if (bidi) {
|
if (bidi) {
|
||||||
/* TODO */
|
const uint64_t next = qcc->next_bidi_l / 4;
|
||||||
return 0;
|
BUG_ON(qcc->rfctl.ms_bidi < next);
|
||||||
|
return qcc->rfctl.ms_bidi - next;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const uint64_t next = qcc->next_uni_l / 4;
|
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;
|
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>
|
/* Handle a new RESET_STREAM frame from stream ID <id> with error code <err>
|
||||||
* and final stream size <final_size>.
|
* 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;
|
rparams = &conn->handle.qc->tx.params;
|
||||||
qfctl_init(&qcc->tx.fc, rparams->initial_max_data);
|
qfctl_init(&qcc->tx.fc, rparams->initial_max_data);
|
||||||
qcc->rfctl.ms_uni = rparams->initial_max_streams_uni;
|
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_l = rparams->initial_max_stream_data_bidi_local;
|
||||||
qcc->rfctl.msd_bidi_r = rparams->initial_max_stream_data_bidi_remote;
|
qcc->rfctl.msd_bidi_r = rparams->initial_max_stream_data_bidi_remote;
|
||||||
qcc->rfctl.msd_uni_l = rparams->initial_max_stream_data_uni;
|
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;
|
break;
|
||||||
case QUIC_FT_MAX_STREAMS_BIDI:
|
case QUIC_FT_MAX_STREAMS_BIDI:
|
||||||
case QUIC_FT_MAX_STREAMS_UNI:
|
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;
|
break;
|
||||||
case QUIC_FT_DATA_BLOCKED:
|
case QUIC_FT_DATA_BLOCKED:
|
||||||
qc->cntrs.data_blocked++;
|
qc->cntrs.data_blocked++;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user