]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: qc_prep_app_pkts() implementation
authorFrédéric Lécaille <flecaille@haproxy.com>
Fri, 25 Feb 2022 16:15:21 +0000 (17:15 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 4 Mar 2022 16:00:12 +0000 (17:00 +0100)
We want to get rid of the code used during the handshake step. qc_prep_app_pkts()
aim is to build short packets which are also datagrams.
Make quic_conn_app_io_cb() call this new function to prepare short packets.

src/xprt_quic.c

index 80950b655fdfaa6b0aad94360f28ca91c18c62d2..336588af151d2e77bfe99d65e5fdb426118cd917 100644 (file)
@@ -2453,6 +2453,124 @@ static inline void qc_set_dg(struct cbuf *cbuf,
        cb_add(cbuf, dglen + sizeof dglen + sizeof pkt);
 }
 
+/* Prepare as much as possible short packets which are also datagrams into <qr>
+ * ring buffer for the QUIC connection with <ctx> as I/O handler context.
+ * A header made of two fields is added to each datagram: the datagram length followed
+ * by the address of the first packet in this datagram.
+ * Returns 1 if succeeded, or 0 if something wrong happened.
+ */
+static int qc_prep_app_pkts(struct quic_conn *qc, struct qring *qr)
+{
+       struct quic_enc_level *qel;
+       struct cbuf *cbuf;
+       unsigned char *end_buf, *end, *pos, *spos;
+       struct quic_tx_packet *pkt;
+       size_t total;
+       size_t dg_headlen;
+
+       TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc);
+       /* Each datagram is prepended with its length followed by the
+        * address of the first packet in the datagram.
+        */
+       dg_headlen = sizeof(uint16_t) + sizeof pkt;
+       qel = &qc->els[QUIC_TLS_ENC_LEVEL_APP];
+       total = 0;
+ start:
+       cbuf = qr->cbuf;
+       spos = pos = cb_wr(cbuf);
+       /* Leave at least <sizeof(uint16_t)> bytes at the end of this buffer
+        * to ensure there is enough room to mark the end of prepared
+        * contiguous data with a zero length.
+        */
+       end_buf = pos + cb_contig_space(cbuf) - sizeof(uint16_t);
+       while (end_buf - pos >= (int)qc->path->mtu + dg_headlen) {
+               int err, probe, ack, cc;
+
+               TRACE_POINT(QUIC_EV_CONN_PHPKTS, qc, qel);
+               probe = ack = 0;
+               cc =  HA_ATOMIC_LOAD(&qc->flags) & QUIC_FL_CONN_IMMEDIATE_CLOSE;
+               if (!cc) {
+                       probe = qel->pktns->tx.pto_probe;
+                       ack = HA_ATOMIC_BTR(&qel->pktns->flags, QUIC_FL_PKTNS_ACK_REQUIRED_BIT);
+               }
+               /* Do not build any more packet if the TX secrets are not available or
+                * if there is nothing to send, i.e. if no CONNECTION_CLOSE or ACK are required
+                * and if there is no more packets to send upon PTO expiration
+                * and if there is no more CRYPTO data available or in flight
+                * congestion control limit is reached for prepared data
+                */
+               if (!(qel->tls_ctx.flags & QUIC_FL_TLS_SECRETS_SET) ||
+                   (!cc && !ack && !probe &&
+                    (LIST_ISEMPTY(&qel->pktns->tx.frms) ||
+                     qc->path->prep_in_flight >= qc->path->cwnd))) {
+                       TRACE_DEVEL("nothing more to do", QUIC_EV_CONN_PHPKTS, qc);
+                       break;
+               }
+
+               /* Leave room for the datagram header */
+               pos += dg_headlen;
+               if (!quic_peer_validated_addr(qc) && qc_is_listener(qc)) {
+                       end = pos + QUIC_MIN(qc->path->mtu, 3 * qc->rx.bytes - qc->tx.prep_bytes);
+               }
+               else {
+                       end = pos + qc->path->mtu;
+               }
+
+               pkt = qc_build_pkt(&pos, end, qel, qc, 0, 0,
+                                  QUIC_PACKET_TYPE_SHORT, ack, probe, cc, &err);
+               /* Restore the PTO dgrams counter if a packet could not be built */
+               if (err < 0) {
+                       if (ack)
+                               HA_ATOMIC_BTS(&qel->pktns->flags, QUIC_FL_PKTNS_ACK_REQUIRED_BIT);
+               }
+               switch (err) {
+               case -2:
+                       goto err;
+               case -1:
+                       goto out;
+               default:
+                       break;
+               }
+
+               /* This is to please to GCC. We cannot have (err >= 0 && !pkt) */
+               if (!pkt)
+                       goto err;
+
+               total += pkt->len;
+               /* Set the current datagram as prepared into <cbuf>. */
+               qc_set_dg(cbuf, pkt->len, pkt);
+       }
+
+ stop_build:
+       /* Reset <wr> writer index if in front of <rd> index */
+       if (end_buf - pos < (int)qc->path->mtu + dg_headlen) {
+               int rd = HA_ATOMIC_LOAD(&cbuf->rd);
+
+               TRACE_DEVEL("buffer full", QUIC_EV_CONN_PHPKTS, qc);
+               if (cb_contig_space(cbuf) >= sizeof(uint16_t)) {
+                       if ((pos != spos && cbuf->wr > rd) || (pos == spos && rd <= cbuf->wr)) {
+                               /* Mark the end of contiguous data for the reader */
+                               write_u16(cb_wr(cbuf), 0);
+                               cb_add(cbuf, sizeof(uint16_t));
+                       }
+               }
+
+               if (rd && rd <= cbuf->wr) {
+                       cb_wr_reset(cbuf);
+                       /* Let's try to reuse this buffer */
+                       goto start;
+               }
+       }
+
+ out:
+       TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
+       return total;
+
+ err:
+       TRACE_DEVEL("leaving in error", QUIC_EV_CONN_PHPKTS, qc);
+       return -1;
+}
+
 /* Prepare as much as possible packets into <qr> ring buffer for
  * the QUIC connection with <ctx> as I/O handler context, possibly concatenating
  * several packets in the same datagram. A header made of two fields is added
@@ -3168,7 +3286,7 @@ static int qc_send_app_pkts(struct quic_conn *qc)
                /* Never happens */
                return 1;
 
-       ret = qc_prep_pkts(qc, qr, QUIC_TLS_ENC_LEVEL_APP, QUIC_TLS_ENC_LEVEL_NONE);
+       ret = qc_prep_app_pkts(qc, qr);
        if (ret == -1)
                goto err;
        else if (ret == 0)