From c206f2aa62ace93ce06a940e6992ffb4f3316bb5 Mon Sep 17 00:00:00 2001 From: Hugo Landau Date: Thu, 13 Jul 2023 11:36:24 +0100 Subject: [PATCH] QUIC TXP: Refactor TXP-related deadline handling into TXP Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/21458) --- include/internal/quic_txp.h | 12 +++++++++++ ssl/quic/quic_channel.c | 12 ++++------- ssl/quic/quic_txp.c | 42 ++++++++++++++++++++++++++++++++----- 3 files changed, 53 insertions(+), 13 deletions(-) diff --git a/include/internal/quic_txp.h b/include/internal/quic_txp.h index c5a4c44a52f..74590749fc3 100644 --- a/include/internal/quic_txp.h +++ b/include/internal/quic_txp.h @@ -90,6 +90,18 @@ typedef struct quic_txp_status_st { int ossl_quic_tx_packetiser_generate(OSSL_QUIC_TX_PACKETISER *txp, QUIC_TXP_STATUS *status); +/* + * Returns a deadline after which a call to ossl_quic_tx_packetiser_generate() + * might succeed even if it did not previously. This may return + * ossl_time_infinite() if there is no such deadline currently applicable. It + * returns ossl_time_zero() if there is (potentially) more data to be generated + * immediately. The value returned is liable to change after any call to + * ossl_quic_tx_packetiser_generate() (or after ACKM or CC state changes). Note + * that ossl_quic_tx_packetiser_generate() can also start to succeed for other + * non-chronological reasons, such as changes to send stream buffers, etc. + */ +OSSL_TIME ossl_quic_tx_packetiser_get_deadline(OSSL_QUIC_TX_PACKETISER *txp); + /* * Set the token used in Initial packets. The callback is called when the buffer * is no longer needed; for example, when the TXP is freed or when this function diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index b8d6e126656..6b009acfdec 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -2126,9 +2126,7 @@ static int ch_tx(QUIC_CHANNEL *ch) * Best effort. In particular if TXP fails for some reason we should still * flush any queued packets which we already generated. */ - switch (ossl_quic_tx_packetiser_generate(ch->txp, - TX_PACKETISER_ARCHETYPE_NORMAL, - &status)) { + switch (ossl_quic_tx_packetiser_generate(ch->txp, &status)) { case TX_PACKETISER_RES_SENT_PKT: ch->have_sent_any_pkt = 1; /* Packet was sent */ @@ -2212,11 +2210,9 @@ static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch) } } - /* When will CC let us send more? */ - if (ossl_quic_tx_packetiser_has_pending(ch->txp, TX_PACKETISER_ARCHETYPE_NORMAL, - TX_PACKETISER_BYPASS_CC)) - deadline = ossl_time_min(deadline, - ch->cc_method->get_wakeup_deadline(ch->cc_data)); + /* Apply TXP wakeup deadline. */ + deadline = ossl_time_min(deadline, + ossl_quic_tx_packetiser_get_deadline(ch->txp)); /* Is the terminating timer armed? */ if (ossl_quic_channel_is_terminating(ch)) diff --git a/ssl/quic/quic_txp.c b/ssl/quic/quic_txp.c index 287288c5593..15095c7d9e8 100644 --- a/ssl/quic/quic_txp.c +++ b/ssl/quic/quic_txp.c @@ -440,7 +440,8 @@ static int txp_pkt_append_padding(struct txp_pkt *pkt, OSSL_QUIC_TX_PACKETISER *txp, size_t num_bytes); static int txp_pkt_commit(OSSL_QUIC_TX_PACKETISER *txp, struct txp_pkt *pkt, uint32_t archetype); -static uint32_t txp_determine_archetype(OSSL_QUIC_TX_PACKETISER *txp); +static uint32_t txp_determine_archetype(OSSL_QUIC_TX_PACKETISER *txp, + uint64_t cc_limit); OSSL_QUIC_TX_PACKETISER *ossl_quic_tx_packetiser_new(const OSSL_QUIC_TX_PACKETISER_ARGS *args) { @@ -712,7 +713,7 @@ int ossl_quic_tx_packetiser_generate(OSSL_QUIC_TX_PACKETISER *txp, ossl_qtx_finish_dgram(txp->args.qtx); /* 1. Archetype Selection */ - archetype = txp_determine_archetype(txp); + archetype = txp_determine_archetype(txp, cc_limit); /* 2. Packet Staging */ for (enc_level = QUIC_ENC_LEVEL_INITIAL; @@ -1166,12 +1167,11 @@ static int txp_determine_geometry(OSSL_QUIC_TX_PACKETISER *txp, return 1; } -static uint32_t txp_determine_archetype(OSSL_QUIC_TX_PACKETISER *txp) +static uint32_t txp_determine_archetype(OSSL_QUIC_TX_PACKETISER *txp, + uint64_t cc_limit) { OSSL_ACKM_PROBE_INFO *probe_info = ossl_ackm_get0_probe_request(txp->args.ackm); - uint64_t cc_limit - = txp->args.cc_method->get_tx_allowance(txp->args.cc_data); uint32_t pn_space; /* @@ -2933,3 +2933,35 @@ QUIC_PN ossl_quic_tx_packetiser_get_next_pn(OSSL_QUIC_TX_PACKETISER *txp, return txp->next_pn[pn_space]; } + +OSSL_TIME ossl_quic_tx_packetiser_get_deadline(OSSL_QUIC_TX_PACKETISER *txp) +{ + /* + * TXP-specific deadline computations which rely on TXP innards. This is in + * turn relied on by the QUIC_CHANNEL code to determine the channel event + * handling deadline. + */ + OSSL_TIME deadline = ossl_time_infinite(); + uint32_t enc_level, pn_space; + + /* + * ACK generation is not CC-gated - packets containing only ACKs are allowed + * to bypass CC. We want to generate ACK frames even if we are currently + * restricted by CC so the peer knows we have received data. The generate + * call will take care of selecting the correct packet archetype. + */ + for (enc_level = QUIC_ENC_LEVEL_INITIAL; + enc_level < QUIC_ENC_LEVEL_NUM; + ++enc_level) + if (ossl_qtx_is_enc_level_provisioned(txp->args.qtx, enc_level)) { + pn_space = ossl_quic_enc_level_to_pn_space(enc_level); + deadline = ossl_time_min(deadline, + ossl_ackm_get_ack_deadline(txp->args.ackm, pn_space)); + } + + /* When will CC let us send more? */ + deadline = ossl_time_min(deadline, + txp->args.cc_method->get_wakeup_deadline(txp->args.cc_data)); + + return deadline; +} -- 2.47.2