mirror of
https://github.com/openssl/openssl.git
synced 2025-01-18 13:44:20 +08:00
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)
This commit is contained in:
parent
e2212b20bc
commit
fee8f48e35
@ -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;
|
||||
|
@ -1086,6 +1086,93 @@ static const struct script_op script_14[] = {
|
||||
OP_END
|
||||
};
|
||||
|
||||
/* 15. INITIAL, Anti-Deadlock Probe Simulation */
|
||||
static int gen_probe_initial(struct helper *h)
|
||||
{
|
||||
OSSL_ACKM_PROBE_INFO *probe = ossl_ackm_get_probe_request(h->args.ackm);
|
||||
|
||||
/*
|
||||
* Pretend the ACKM asked for an anti-deadlock Initial probe.
|
||||
* We test output of this in the ACKM unit tests.
|
||||
*/
|
||||
++probe->anti_deadlock_initial;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct script_op script_15[] = {
|
||||
OP_PROVIDE_SECRET(QUIC_ENC_LEVEL_INITIAL, QRL_SUITE_AES128GCM, secret_1)
|
||||
OP_TXP_GENERATE_NONE(TX_PACKETISER_ARCHETYPE_NORMAL)
|
||||
OP_CHECK(gen_probe_initial)
|
||||
OP_TXP_GENERATE(TX_PACKETISER_ARCHETYPE_NORMAL)
|
||||
OP_RX_PKT()
|
||||
OP_EXPECT_DGRAM_LEN(1200, 1200)
|
||||
OP_NEXT_FRAME()
|
||||
OP_EXPECT_FRAME(OSSL_QUIC_FRAME_TYPE_PING)
|
||||
OP_EXPECT_NO_FRAME()
|
||||
OP_RX_PKT_NONE()
|
||||
OP_TXP_GENERATE_NONE(TX_PACKETISER_ARCHETYPE_NORMAL)
|
||||
OP_END
|
||||
};
|
||||
|
||||
/* 16. HANDSHAKE, Anti-Deadlock Probe Simulation */
|
||||
static int gen_probe_handshake(struct helper *h)
|
||||
{
|
||||
OSSL_ACKM_PROBE_INFO *probe = ossl_ackm_get_probe_request(h->args.ackm);
|
||||
|
||||
/*
|
||||
* Pretend the ACKM asked for an anti-deadlock Handshake probe.
|
||||
* We test output of this in the ACKM unit tests.
|
||||
*/
|
||||
++probe->anti_deadlock_handshake;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct script_op script_16[] = {
|
||||
OP_DISCARD_EL(QUIC_ENC_LEVEL_INITIAL)
|
||||
OP_PROVIDE_SECRET(QUIC_ENC_LEVEL_HANDSHAKE, QRL_SUITE_AES128GCM, secret_1)
|
||||
OP_TXP_GENERATE_NONE(TX_PACKETISER_ARCHETYPE_NORMAL)
|
||||
OP_CHECK(gen_probe_handshake)
|
||||
OP_TXP_GENERATE(TX_PACKETISER_ARCHETYPE_NORMAL)
|
||||
OP_RX_PKT()
|
||||
OP_EXPECT_DGRAM_LEN(21, 512)
|
||||
OP_NEXT_FRAME()
|
||||
OP_EXPECT_FRAME(OSSL_QUIC_FRAME_TYPE_PING)
|
||||
OP_EXPECT_NO_FRAME()
|
||||
OP_RX_PKT_NONE()
|
||||
OP_TXP_GENERATE_NONE(TX_PACKETISER_ARCHETYPE_NORMAL)
|
||||
OP_END
|
||||
};
|
||||
|
||||
/* 17. 1-RTT, Probe Simulation */
|
||||
static int gen_probe_1rtt(struct helper *h)
|
||||
{
|
||||
OSSL_ACKM_PROBE_INFO *probe = ossl_ackm_get_probe_request(h->args.ackm);
|
||||
|
||||
/*
|
||||
* Pretend the ACKM asked for a 1-RTT PTO probe.
|
||||
* We test output of this in the ACKM unit tests.
|
||||
*/
|
||||
++probe->pto[QUIC_PN_SPACE_APP];
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct script_op script_17[] = {
|
||||
OP_DISCARD_EL(QUIC_ENC_LEVEL_INITIAL)
|
||||
OP_DISCARD_EL(QUIC_ENC_LEVEL_HANDSHAKE)
|
||||
OP_PROVIDE_SECRET(QUIC_ENC_LEVEL_1RTT, QRL_SUITE_AES128GCM, secret_1)
|
||||
OP_TXP_GENERATE_NONE(TX_PACKETISER_ARCHETYPE_NORMAL)
|
||||
OP_CHECK(gen_probe_1rtt)
|
||||
OP_TXP_GENERATE(TX_PACKETISER_ARCHETYPE_NORMAL)
|
||||
OP_RX_PKT()
|
||||
OP_EXPECT_DGRAM_LEN(21, 512)
|
||||
OP_NEXT_FRAME()
|
||||
OP_EXPECT_FRAME(OSSL_QUIC_FRAME_TYPE_PING)
|
||||
OP_EXPECT_NO_FRAME()
|
||||
OP_RX_PKT_NONE()
|
||||
OP_TXP_GENERATE_NONE(TX_PACKETISER_ARCHETYPE_NORMAL)
|
||||
OP_END
|
||||
};
|
||||
|
||||
static const struct script_op *const scripts[] = {
|
||||
script_1,
|
||||
script_2,
|
||||
@ -1100,7 +1187,10 @@ static const struct script_op *const scripts[] = {
|
||||
script_11,
|
||||
script_12,
|
||||
script_13,
|
||||
script_14
|
||||
script_14,
|
||||
script_15,
|
||||
script_16,
|
||||
script_17
|
||||
};
|
||||
|
||||
static void skip_padding(struct helper *h)
|
||||
|
Loading…
Reference in New Issue
Block a user