]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: refactor qc_prep_pkts() loop
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 30 May 2024 12:53:06 +0000 (14:53 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 12 Jun 2024 16:05:40 +0000 (18:05 +0200)
qc_prep_pkts() is built around a double loop iteration. First, it
iterates over every QEL instance register on sending. The inner loop is
used to repeatdly called qc_build_pkt() with a QEL instance. If the QEL
instance has no more data to sent, the next QEL entry is selected. It
can also be interrupted earlier if there is not enough room on the sent
buffer.

Clarify the inner loop by using qc_may_build_pkt() directly into it
besides the check on buffer room left. This function is used to test if
the QEL instance has something to send.

This should simplify send evolution, in particular GSO implementation.

src/quic_tx.c

index 0b74c23a8628566882324032add8dac3ae407182..215a4cbd547b11a25e58b7b3b489820a77f517ec 100644 (file)
@@ -512,6 +512,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
                const struct quic_version *ver;
                struct list *frms = qel->send_frms;
                struct quic_enc_level *next_qel;
+               int probe, must_ack;
 
                if (qel == qc->eel) {
                        /* Next encryption level */
@@ -524,40 +525,21 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
                next_qel = LIST_NEXT(&qel->el_send, struct quic_enc_level *, el_send);
                if (&next_qel->el_send == qels)
                        next_qel = NULL;
+               /* We do not probe if an immediate close was asked */
+               probe = !cc ? qel->pktns->tx.pto_probe : 0;
 
-               /* Build as much as datagrams at <qel> encryption level.
-                * Each datagram is prepended with its length followed by the address
-                * of the first packet in the datagram (QUIC_DGRAM_HEADLEN).
+               /* Build packets for QEL until nothing to send (and no padding
+                * required anymore) while there is still room left in buffer.
                 */
-               while (b_contig_space(buf) > QUIC_DGRAM_HEADLEN || prv_pkt) {
-                       int probe, must_ack;
+               while (b_contig_space(buf) >= QUIC_DGRAM_HEADLEN &&
+                      (qc_may_build_pkt(qc, frms, qel, cc, probe, &must_ack) ||
+                       (padding && !next_qel))) {
+
                        enum quic_pkt_type pkt_type;
                        struct quic_tx_packet *cur_pkt;
                        enum qc_build_pkt_err err;
 
                        TRACE_PROTO("TX prep pkts", QUIC_EV_CONN_PHPKTS, qc, qel);
-                       probe = 0;
-                       /* We do not probe if an immediate close was asked */
-                       if (!cc)
-                               probe = qel->pktns->tx.pto_probe;
-
-                       /* Remove QEL if nothing to send anymore. Padding is only emitted for last QEL. */
-                       if (!qc_may_build_pkt(qc, frms, qel, cc, probe, &must_ack) &&
-                           (!padding || next_qel)) {
-                               /* Remove qel from send_list if nothing to send. */
-                               LIST_DEL_INIT(&qel->el_send);
-                               qel->send_frms = NULL;
-
-                               if (prv_pkt && !next_qel) {
-                                       qc_txb_store(buf, dglen, first_pkt);
-                                       /* Build only one datagram when an immediate close is required. */
-                                       if (cc)
-                                               goto out;
-                               }
-
-                               TRACE_DEVEL("next encryption level", QUIC_EV_CONN_PHPKTS, qc);
-                               break;
-                       }
 
                        /* On starting a new datagram, calculate end max offset
                         * to stay under MTU limit.
@@ -631,6 +613,11 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
                        total += cur_pkt->len;
                        dglen += cur_pkt->len;
 
+                       /* qc_do_build_pkt() is responsible to decrement probe
+                        * value. Required to break loop on qc_may_build_pkt().
+                        */
+                       probe = qel->pktns->tx.pto_probe;
+
                        /* Reset padding if datagram is big enough. */
                        if (dglen >= QUIC_INITIAL_PACKET_MINLEN)
                                padding = 0;
@@ -649,27 +636,34 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
                                cur_pkt->flags |= QUIC_FL_TX_PACKET_COALESCED;
                        }
 
-                       /* If there is no more packet to build for this encryption level,
-                        * select the next one <next_qel>, if any, to coalesce a packet in
-                        * the same datagram, except if <qel> is the Application data
-                        * encryption level which cannot be selected to do that.
-                        */
-                       if (LIST_ISEMPTY(frms) && next_qel) {
+                       /* Build only one datagram when an immediate close is required. */
+                       if (cc) {
+                               qc_txb_store(buf, dglen, first_pkt);
+                               goto out;
+                       }
+
+                       if (LIST_ISEMPTY(frms)) {
                                prv_pkt = cur_pkt;
                        }
                        else {
+                               /* Finalize current datagram if not all frames
+                                * left. This is due to full buffer or datagram
+                                * MTU reached.
+                                */
                                qc_txb_store(buf, dglen, first_pkt);
-                               /* Build only one datagram when an immediate close is required. */
-                               if (cc)
-                                       goto out;
                                first_pkt = NULL;
                                dglen = 0;
                                padding = 0;
                                prv_pkt = NULL;
                        }
                }
+
+               TRACE_DEVEL("next encryption level", QUIC_EV_CONN_PHPKTS, qc);
        }
 
+       if (first_pkt)
+               qc_txb_store(buf, dglen, first_pkt);
+
  out:
        if (cc && total) {
                BUG_ON(buf != &qc->tx.cc_buf);