QUIC TXP: Refactor TXP-related deadline handling into TXP
authorHugo Landau <hlandau@openssl.org>
Thu, 13 Jul 2023 10:36:24 +0000 (11:36 +0100)
committerTomas Mraz <tomas@openssl.org>
Fri, 21 Jul 2023 06:43:52 +0000 (08:43 +0200)
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21458)

include/internal/quic_txp.h
ssl/quic/quic_channel.c
ssl/quic/quic_txp.c

index c5a4c44a52f36f6e333f06333b6aef991343649d..74590749fc3451f071132098e0ecb8dde4d4b77f 100644 (file)
@@ -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
index b8d6e126656120809895a355b9a64e69619c12c0..6b009acfdecb536b7f469d5f8508a13d8de53645 100644 (file)
@@ -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))
index 287288c55939be5c234bd88e88e3a2fd4cdd60f7..15095c7d9e8c0cff0da1964e0135fa7bc3d95181 100644 (file)
@@ -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;
+}