summaryrefslogtreecommitdiff
path: root/ssl
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2022-12-16 10:57:11 +0000
committerTomas Mraz <tomas@openssl.org>2023-01-30 09:44:59 +0100
commitfee8f48e35f7009065227ae76c50672632ea5c40 (patch)
tree0b73af4f84c459c10adf296d43cc3bbc695b4d95 /ssl
parente2212b20bcf96c62c17a5e124c3bd61a98b8fcfd (diff)
downloadopenssl-new-fee8f48e35f7009065227ae76c50672632ea5c40.tar.gz
QUIC TXP: Allow TXP to generate probes
Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/19925)
Diffstat (limited to 'ssl')
-rw-r--r--ssl/quic/quic_txp.c96
1 files changed, 81 insertions, 15 deletions
diff --git a/ssl/quic/quic_txp.c b/ssl/quic/quic_txp.c
index 20e8533b7f..5be9c2b7f8 100644
--- a/ssl/quic/quic_txp.c
+++ b/ssl/quic/quic_txp.c
@@ -313,9 +313,11 @@ static void on_regen_notify(uint64_t frame_type, uint64_t stream_id,
static int sstream_is_pending(QUIC_SSTREAM *sstream);
static int txp_el_pending(OSSL_QUIC_TX_PACKETISER *txp, uint32_t enc_level,
uint32_t archetype,
+ int cc_can_send,
uint32_t *conn_close_enc_level);
static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER *txp, uint32_t enc_level,
uint32_t archetype,
+ int cc_can_send,
int is_last_in_dgram,
int dgram_contains_initial,
int chosen_for_conn_close);
@@ -476,14 +478,16 @@ int ossl_quic_tx_packetiser_has_pending(OSSL_QUIC_TX_PACKETISER *txp,
{
uint32_t enc_level, conn_close_enc_level = QUIC_ENC_LEVEL_NUM;
int bypass_cc = ((flags & TX_PACKETISER_BYPASS_CC) != 0);
+ int cc_can_send;
- if (!bypass_cc && !txp->args.cc_method->can_send(txp->args.cc_data))
- return 0;
+ cc_can_send
+ = (bypass_cc || txp->args.cc_method->can_send(txp->args.cc_data));
for (enc_level = QUIC_ENC_LEVEL_INITIAL;
enc_level < QUIC_ENC_LEVEL_NUM;
++enc_level)
- if (txp_el_pending(txp, enc_level, archetype, &conn_close_enc_level))
+ if (txp_el_pending(txp, enc_level, archetype, cc_can_send,
+ &conn_close_enc_level))
return 1;
return 0;
@@ -498,17 +502,20 @@ int ossl_quic_tx_packetiser_generate(OSSL_QUIC_TX_PACKETISER *txp,
uint32_t archetype)
{
uint32_t enc_level, conn_close_enc_level = QUIC_ENC_LEVEL_NUM;
- int have_pkt_for_el[QUIC_ENC_LEVEL_NUM], is_last_in_dgram;
+ int have_pkt_for_el[QUIC_ENC_LEVEL_NUM], is_last_in_dgram, cc_can_send;
size_t num_el_in_dgram = 0, pkts_done = 0;
int rc;
- if (!txp->args.cc_method->can_send(txp->args.cc_data))
- return TX_PACKETISER_RES_NO_PKT;
+ /*
+ * If CC says we cannot send we still may be able to send any queued probes.
+ */
+ cc_can_send = txp->args.cc_method->can_send(txp->args.cc_data);
for (enc_level = QUIC_ENC_LEVEL_INITIAL;
enc_level < QUIC_ENC_LEVEL_NUM;
++enc_level) {
have_pkt_for_el[enc_level] = txp_el_pending(txp, enc_level, archetype,
+ cc_can_send,
&conn_close_enc_level);
if (have_pkt_for_el[enc_level])
++num_el_in_dgram;
@@ -530,7 +537,8 @@ int ossl_quic_tx_packetiser_generate(OSSL_QUIC_TX_PACKETISER *txp,
continue;
is_last_in_dgram = (pkts_done + 1 == num_el_in_dgram);
- rc = txp_generate_for_el(txp, enc_level, archetype, is_last_in_dgram,
+ rc = txp_generate_for_el(txp, enc_level, archetype, cc_can_send,
+ is_last_in_dgram,
have_pkt_for_el[QUIC_ENC_LEVEL_INITIAL],
enc_level == conn_close_enc_level);
@@ -739,6 +747,7 @@ static int txp_get_archetype_data(uint32_t enc_level,
*/
static int txp_el_pending(OSSL_QUIC_TX_PACKETISER *txp, uint32_t enc_level,
uint32_t archetype,
+ int cc_can_send,
uint32_t *conn_close_enc_level)
{
struct archetype_data a;
@@ -754,6 +763,23 @@ static int txp_el_pending(OSSL_QUIC_TX_PACKETISER *txp, uint32_t enc_level,
if (!txp_get_archetype_data(enc_level, archetype, &a))
return 0;
+ /* Do we need to send a PTO probe? */
+ if (a.allow_force_ack_eliciting) {
+ OSSL_ACKM_PROBE_INFO *probe_info
+ = ossl_ackm_get_probe_request(txp->args.ackm);
+
+ if ((enc_level == QUIC_ENC_LEVEL_INITIAL
+ && probe_info->anti_deadlock_initial > 0)
+ || (enc_level == QUIC_ENC_LEVEL_HANDSHAKE
+ && probe_info->anti_deadlock_handshake > 0)
+ || probe_info->pto[pn_space] > 0)
+ return 1;
+ }
+
+ if (!cc_can_send)
+ /* If CC says we cannot currently send, we can only send probes. */
+ return 0;
+
/* Does the crypto stream for this EL want to produce anything? */
if (a.allow_crypto && sstream_is_pending(txp->args.crypto[pn_space]))
return 1;
@@ -859,6 +885,7 @@ static int sstream_is_pending(QUIC_SSTREAM *sstream)
*/
static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER *txp, uint32_t enc_level,
uint32_t archetype,
+ int cc_can_send,
int is_last_in_dgram,
int dgram_contains_initial,
int chosen_for_conn_close)
@@ -877,11 +904,20 @@ static int txp_generate_for_el(OSSL_QUIC_TX_PACKETISER *txp, uint32_t enc_level,
time_since_last = ossl_time_subtract(txp->args.now(txp->args.now_arg),
txp->last_tx_time);
- cc_limit_ = txp->args.cc_method->get_send_allowance(txp->args.cc_data,
- time_since_last,
- ossl_time_is_zero(time_since_last));
+ if (!cc_can_send) {
+ /*
+ * If we are called when we cannot send, this must be because we want
+ * to generate a probe. In this circumstance, don't clamp based on CC.
+ */
+ cc_limit = SIZE_MAX;
+ } else {
+ /* Allow CC to clamp how much we can send. */
+ cc_limit_ = txp->args.cc_method->get_send_allowance(txp->args.cc_data,
+ time_since_last,
+ ossl_time_is_zero(time_since_last));
- cc_limit = (cc_limit_ > SIZE_MAX ? SIZE_MAX : (size_t)cc_limit_);
+ cc_limit = (cc_limit_ > SIZE_MAX ? SIZE_MAX : (size_t)cc_limit_);
+ }
/* Assemble packet header. */
phdr.type = ossl_quic_enc_level_to_pkt_type(enc_level);
@@ -1781,18 +1817,30 @@ static int txp_generate_for_el_actual(OSSL_QUIC_TX_PACKETISER *txp,
uint32_t pn_space = ossl_quic_enc_level_to_pn_space(enc_level);
struct tx_helper h;
int have_helper = 0, have_ack_eliciting = 0, done_pre_token = 0;
- int require_ack_eliciting;
+ int require_ack_eliciting = 0;
QUIC_CFQ_ITEM *cfq_item;
QUIC_TXPIM_PKT *tpkt = NULL;
OSSL_QTX_PKT pkt;
QUIC_STREAM *tmp_head = NULL, *stream;
+ OSSL_ACKM_PROBE_INFO *probe_info
+ = ossl_ackm_get_probe_request(txp->args.ackm);
if (!txp_get_archetype_data(enc_level, archetype, &a))
goto fatal_err;
- require_ack_eliciting
- = (a.allow_force_ack_eliciting
- && (txp->force_ack_eliciting & (1UL << pn_space)));
+ if (a.allow_force_ack_eliciting) {
+ /*
+ * Make this packet ACK-eliciting if it has been explicitly requested,
+ * or if ACKM has requested a probe for this PN space.
+ */
+ if ((txp->force_ack_eliciting & (1UL << pn_space)) != 0
+ || (enc_level == QUIC_ENC_LEVEL_INITIAL
+ && probe_info->anti_deadlock_initial > 0)
+ || (enc_level == QUIC_ENC_LEVEL_HANDSHAKE
+ && probe_info->anti_deadlock_handshake > 0)
+ || probe_info->pto[pn_space] > 0)
+ require_ack_eliciting = 1;
+ }
/* Minimum cannot be bigger than maximum. */
if (min_ppl > max_ppl)
@@ -2158,6 +2206,24 @@ static int txp_generate_for_el_actual(OSSL_QUIC_TX_PACKETISER *txp,
if (tpkt->had_ack_frame)
txp->want_ack &= ~(1UL << pn_space);
+ /*
+ * Decrement probe request counts if we have sent a packet that meets
+ * the requirement of a probe, namely being ACK-eliciting.
+ */
+ if (have_ack_eliciting) {
+ if (enc_level == QUIC_ENC_LEVEL_INITIAL
+ && probe_info->anti_deadlock_initial > 0)
+ --probe_info->anti_deadlock_initial;
+
+ if (enc_level == QUIC_ENC_LEVEL_HANDSHAKE
+ && probe_info->anti_deadlock_handshake > 0)
+ --probe_info->anti_deadlock_handshake;
+
+ if (a.allow_force_ack_eliciting /* (i.e., not for 0-RTT) */
+ && probe_info->pto[pn_space] > 0)
+ --probe_info->pto[pn_space];
+ }
+
/* Done. */
tx_helper_cleanup(&h);
return rc;