summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2023-04-18 19:30:55 +0100
committerHugo Landau <hlandau@openssl.org>2023-05-12 14:47:12 +0100
commita6b6ea17376572e3c0227b98f21dedc48215aa9a (patch)
treeab532445df770379e066e5a3e46ed588e7dba7e6
parent5bd9ddd86e714705840215b8d2bbb0aedc598e96 (diff)
downloadopenssl-new-a6b6ea17376572e3c0227b98f21dedc48215aa9a.tar.gz
QUIC TXP/CHANNEL: Generate MAX_STREAMS using RXFC
Though the RXFC was designed for stream flow control, its logic is generic enough to use to control MAX_STREAMS generation. Control of when _we_ can open streams is already done in a bespoke fashion and doesn't use a TXFC, however (see ossl_quic_stream_map_update_state). Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/20765)
-rw-r--r--include/internal/quic_txp.h2
-rw-r--r--ssl/quic/quic_channel.c49
-rw-r--r--ssl/quic/quic_channel_local.h6
-rw-r--r--ssl/quic/quic_txp.c37
-rw-r--r--test/quic_txp_test.c30
5 files changed, 85 insertions, 39 deletions
diff --git a/include/internal/quic_txp.h b/include/internal/quic_txp.h
index fb553f97e5..0e4fd5cc49 100644
--- a/include/internal/quic_txp.h
+++ b/include/internal/quic_txp.h
@@ -42,6 +42,8 @@ typedef struct ossl_quic_tx_packetiser_args_st {
QUIC_STREAM_MAP *qsm; /* QUIC Streams Map */
QUIC_TXFC *conn_txfc; /* QUIC Connection-Level TX Flow Controller */
QUIC_RXFC *conn_rxfc; /* QUIC Connection-Level RX Flow Controller */
+ QUIC_RXFC *max_streams_bidi_rxfc; /* QUIC RXFC for MAX_STREAMS generation */
+ QUIC_RXFC *max_streams_uni_rxfc;
const OSSL_CC_METHOD *cc_method; /* QUIC Congestion Controller */
OSSL_CC_DATA *cc_data; /* QUIC Congestion Controller Instance */
OSSL_TIME (*now)(void *arg); /* Callback to get current time. */
diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c
index 3e099e9d93..c689166805 100644
--- a/ssl/quic/quic_channel.c
+++ b/ssl/quic/quic_channel.c
@@ -111,6 +111,8 @@ static int gen_rand_conn_id(OSSL_LIB_CTX *libctx, size_t len, QUIC_CONN_ID *cid)
#define DEFAULT_INIT_STREAM_RXFC_WND (2 * 1024 * 1024)
#define DEFAULT_STREAM_RXFC_MAX_WND_MUL 5
+#define DEFAULT_INIT_CONN_MAX_STREAMS 100
+
static int ch_init(QUIC_CHANNEL *ch)
{
OSSL_QUIC_TX_PACKETISER_ARGS txp_args = {0};
@@ -160,6 +162,16 @@ static int ch_init(QUIC_CHANNEL *ch)
get_time, ch))
goto err;
+ if (!ossl_quic_rxfc_init_for_stream_count(&ch->max_streams_bidi_rxfc,
+ DEFAULT_INIT_CONN_MAX_STREAMS,
+ get_time, ch))
+ goto err;
+
+ if (!ossl_quic_rxfc_init_for_stream_count(&ch->max_streams_uni_rxfc,
+ DEFAULT_INIT_CONN_MAX_STREAMS,
+ get_time, ch))
+ goto err;
+
if (!ossl_statm_init(&ch->statm))
goto err;
@@ -172,25 +184,29 @@ static int ch_init(QUIC_CHANNEL *ch)
ch->cc_method, ch->cc_data)) == NULL)
goto err;
- if (!ossl_quic_stream_map_init(&ch->qsm, get_stream_limit, ch))
+ if (!ossl_quic_stream_map_init(&ch->qsm, get_stream_limit, ch,
+ &ch->max_streams_bidi_rxfc,
+ &ch->max_streams_uni_rxfc))
goto err;
ch->have_qsm = 1;
/* We use a zero-length SCID. */
- txp_args.cur_dcid = ch->init_dcid;
- txp_args.ack_delay_exponent = 3;
- txp_args.qtx = ch->qtx;
- txp_args.txpim = ch->txpim;
- txp_args.cfq = ch->cfq;
- txp_args.ackm = ch->ackm;
- txp_args.qsm = &ch->qsm;
- txp_args.conn_txfc = &ch->conn_txfc;
- txp_args.conn_rxfc = &ch->conn_rxfc;
- txp_args.cc_method = ch->cc_method;
- txp_args.cc_data = ch->cc_data;
- txp_args.now = get_time;
- txp_args.now_arg = ch;
+ txp_args.cur_dcid = ch->init_dcid;
+ txp_args.ack_delay_exponent = 3;
+ txp_args.qtx = ch->qtx;
+ txp_args.txpim = ch->txpim;
+ txp_args.cfq = ch->cfq;
+ txp_args.ackm = ch->ackm;
+ txp_args.qsm = &ch->qsm;
+ txp_args.conn_txfc = &ch->conn_txfc;
+ txp_args.conn_rxfc = &ch->conn_rxfc;
+ txp_args.max_streams_bidi_rxfc = &ch->max_streams_bidi_rxfc;
+ txp_args.max_streams_uni_rxfc = &ch->max_streams_uni_rxfc;
+ txp_args.cc_method = ch->cc_method;
+ txp_args.cc_data = ch->cc_data;
+ txp_args.now = get_time;
+ txp_args.now_arg = ch;
for (pn_space = QUIC_PN_SPACE_INITIAL; pn_space < QUIC_PN_SPACE_NUM; ++pn_space) {
ch->crypto_send[pn_space] = ossl_quic_sstream_new(INIT_CRYPTO_BUF_LEN);
if (ch->crypto_send[pn_space] == NULL)
@@ -1215,13 +1231,12 @@ static int ch_generate_transport_params(QUIC_CHANNEL *ch)
ch->tx_init_max_stream_data_uni))
goto err;
- /* TODO(QUIC): MAX_STREAMS modelling */
if (!ossl_quic_wire_encode_transport_param_int(&wpkt, QUIC_TPARAM_INITIAL_MAX_STREAMS_BIDI,
- ch->is_server ? 100 : 100))
+ ossl_quic_rxfc_get_cwm(&ch->max_streams_bidi_rxfc)))
goto err;
if (!ossl_quic_wire_encode_transport_param_int(&wpkt, QUIC_TPARAM_INITIAL_MAX_STREAMS_UNI,
- 100))
+ ossl_quic_rxfc_get_cwm(&ch->max_streams_uni_rxfc)))
goto err;
if (!WPACKET_get_total_written(&wpkt, &buf_len))
diff --git a/ssl/quic/quic_channel_local.h b/ssl/quic/quic_channel_local.h
index f13d0118ee..379528b516 100644
--- a/ssl/quic/quic_channel_local.h
+++ b/ssl/quic/quic_channel_local.h
@@ -69,9 +69,13 @@ struct quic_channel_st {
OSSL_QUIC_TX_PACKETISER *txp;
QUIC_TXPIM *txpim;
QUIC_CFQ *cfq;
- /* Connection level FC. */
+ /*
+ * Connection level FC. The stream_count RXFCs is used to manage
+ * MAX_STREAMS signalling.
+ */
QUIC_TXFC conn_txfc;
QUIC_RXFC conn_rxfc;
+ QUIC_RXFC max_streams_bidi_rxfc, max_streams_uni_rxfc;
QUIC_STREAM_MAP qsm;
OSSL_STATM statm;
OSSL_CC_DATA *cc_data;
diff --git a/ssl/quic/quic_txp.c b/ssl/quic/quic_txp.c
index 97a88c3ff1..10a1a5f18e 100644
--- a/ssl/quic/quic_txp.c
+++ b/ssl/quic/quic_txp.c
@@ -351,7 +351,9 @@ OSSL_QUIC_TX_PACKETISER *ossl_quic_tx_packetiser_new(const OSSL_QUIC_TX_PACKETIS
|| args->ackm == NULL
|| args->qsm == NULL
|| args->conn_txfc == NULL
- || args->conn_rxfc == NULL) {
+ || args->conn_rxfc == NULL
+ || args->max_streams_bidi_rxfc == NULL
+ || args->max_streams_uni_rxfc == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
@@ -807,8 +809,13 @@ static int txp_el_pending(OSSL_QUIC_TX_PACKETISER *txp, uint32_t enc_level,
return 1;
/* Do we want to produce a MAX_STREAMS frame? */
- if (a.allow_conn_fc && (txp->want_max_streams_bidi
- || txp->want_max_streams_uni))
+ if (a.allow_conn_fc
+ && (txp->want_max_streams_bidi
+ || ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc,
+ 0)
+ || txp->want_max_streams_uni
+ || ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc,
+ 0)))
return 1;
/* Do we want to produce a HANDSHAKE_DONE frame? */
@@ -1927,15 +1934,13 @@ static int txp_generate_for_el_actual(OSSL_QUIC_TX_PACKETISER *txp,
}
/* MAX_STREAMS_BIDI (Regenerate) */
- /*
- * TODO(STREAMS): Once we support multiple streams, add stream count FC
- * and plug this in.
- */
if (a.allow_conn_fc
- && txp->want_max_streams_bidi
+ && (txp->want_max_streams_bidi
+ || ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc, 0))
&& tx_helper_get_space_left(&h) >= MIN_FRAME_SIZE_MAX_STREAMS_BIDI) {
WPACKET *wpkt = tx_helper_begin(&h);
- uint64_t max_streams = 1; /* TODO */
+ uint64_t max_streams
+ = ossl_quic_rxfc_get_cwm(txp->args.max_streams_bidi_rxfc);
if (wpkt == NULL)
goto fatal_err;
@@ -1956,10 +1961,12 @@ static int txp_generate_for_el_actual(OSSL_QUIC_TX_PACKETISER *txp,
/* MAX_STREAMS_UNI (Regenerate) */
if (a.allow_conn_fc
- && txp->want_max_streams_uni
+ && (txp->want_max_streams_uni
+ || ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc, 0))
&& tx_helper_get_space_left(&h) >= MIN_FRAME_SIZE_MAX_STREAMS_UNI) {
WPACKET *wpkt = tx_helper_begin(&h);
- uint64_t max_streams = 0; /* TODO */
+ uint64_t max_streams
+ = ossl_quic_rxfc_get_cwm(txp->args.max_streams_uni_rxfc);
if (wpkt == NULL)
goto fatal_err;
@@ -2209,11 +2216,15 @@ static int txp_generate_for_el_actual(OSSL_QUIC_TX_PACKETISER *txp,
ossl_quic_rxfc_has_cwm_changed(txp->args.conn_rxfc, 1);
}
- if (tpkt->had_max_streams_bidi_frame)
+ if (tpkt->had_max_streams_bidi_frame) {
txp->want_max_streams_bidi = 0;
+ ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_bidi_rxfc, 1);
+ }
- if (tpkt->had_max_streams_uni_frame)
+ if (tpkt->had_max_streams_uni_frame) {
txp->want_max_streams_uni = 0;
+ ossl_quic_rxfc_has_cwm_changed(txp->args.max_streams_uni_rxfc, 1);
+ }
if (tpkt->had_ack_frame)
txp->want_ack &= ~(1UL << pn_space);
diff --git a/test/quic_txp_test.c b/test/quic_txp_test.c
index 265c23fabc..dd85bb5692 100644
--- a/test/quic_txp_test.c
+++ b/test/quic_txp_test.c
@@ -47,6 +47,7 @@ struct helper {
BIO *bio1, *bio2;
QUIC_TXFC conn_txfc;
QUIC_RXFC conn_rxfc, stream_rxfc;
+ QUIC_RXFC max_streams_bidi_rxfc, max_streams_uni_rxfc;
OSSL_STATM statm;
OSSL_CC_DATA *cc_data;
const OSSL_CC_METHOD *cc_method;
@@ -147,6 +148,17 @@ static int helper_init(struct helper *h)
NULL)))
goto err;
+ if (!TEST_true(ossl_quic_rxfc_init(&h->max_streams_bidi_rxfc, NULL,
+ 100, 100,
+ fake_now,
+ NULL)))
+ goto err;
+
+ if (!TEST_true(ossl_quic_rxfc_init(&h->max_streams_uni_rxfc, NULL,
+ 100, 100,
+ fake_now,
+ NULL)))
+
if (!TEST_true(ossl_statm_init(&h->statm)))
goto err;
@@ -171,14 +183,16 @@ static int helper_init(struct helper *h)
if (!TEST_ptr(h->args.crypto[i] = ossl_quic_sstream_new(4096)))
goto err;
- h->args.cur_scid = scid_1;
- h->args.cur_dcid = dcid_1;
- h->args.qsm = &h->qsm;
- h->args.conn_txfc = &h->conn_txfc;
- h->args.conn_rxfc = &h->conn_rxfc;
- h->args.cc_method = h->cc_method;
- h->args.cc_data = h->cc_data;
- h->args.now = fake_now;
+ h->args.cur_scid = scid_1;
+ h->args.cur_dcid = dcid_1;
+ h->args.qsm = &h->qsm;
+ h->args.conn_txfc = &h->conn_txfc;
+ h->args.conn_rxfc = &h->conn_rxfc;
+ h->args.max_streams_bidi_rxfc = &h->max_streams_bidi_rxfc;
+ h->args.max_streams_uni_rxfc = &h->max_streams_uni_rxfc;
+ h->args.cc_method = h->cc_method;
+ h->args.cc_data = h->cc_data;
+ h->args.now = fake_now;
if (!TEST_ptr(h->txp = ossl_quic_tx_packetiser_new(&h->args)))
goto err;