MINOR: quic: refactor qc_prep_pkts() loop

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.
This commit is contained in:
Amaury Denoyelle 2024-05-30 14:53:06 +02:00
parent ba00431625
commit cdfceb10ae

View File

@ -512,6 +512,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
const struct quic_version *ver; const struct quic_version *ver;
struct list *frms = qel->send_frms; struct list *frms = qel->send_frms;
struct quic_enc_level *next_qel; struct quic_enc_level *next_qel;
int probe, must_ack;
if (qel == qc->eel) { if (qel == qc->eel) {
/* Next encryption level */ /* 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); next_qel = LIST_NEXT(&qel->el_send, struct quic_enc_level *, el_send);
if (&next_qel->el_send == qels) if (&next_qel->el_send == qels)
next_qel = NULL; 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. /* Build packets for QEL until nothing to send (and no padding
* Each datagram is prepended with its length followed by the address * required anymore) while there is still room left in buffer.
* of the first packet in the datagram (QUIC_DGRAM_HEADLEN).
*/ */
while (b_contig_space(buf) > QUIC_DGRAM_HEADLEN || prv_pkt) { while (b_contig_space(buf) >= QUIC_DGRAM_HEADLEN &&
int probe, must_ack; (qc_may_build_pkt(qc, frms, qel, cc, probe, &must_ack) ||
(padding && !next_qel))) {
enum quic_pkt_type pkt_type; enum quic_pkt_type pkt_type;
struct quic_tx_packet *cur_pkt; struct quic_tx_packet *cur_pkt;
enum qc_build_pkt_err err; enum qc_build_pkt_err err;
TRACE_PROTO("TX prep pkts", QUIC_EV_CONN_PHPKTS, qc, qel); 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 /* On starting a new datagram, calculate end max offset
* to stay under MTU limit. * 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; total += cur_pkt->len;
dglen += 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. */ /* Reset padding if datagram is big enough. */
if (dglen >= QUIC_INITIAL_PACKET_MINLEN) if (dglen >= QUIC_INITIAL_PACKET_MINLEN)
padding = 0; 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; cur_pkt->flags |= QUIC_FL_TX_PACKET_COALESCED;
} }
/* If there is no more packet to build for this encryption level, /* Build only one datagram when an immediate close is required. */
* select the next one <next_qel>, if any, to coalesce a packet in if (cc) {
* the same datagram, except if <qel> is the Application data qc_txb_store(buf, dglen, first_pkt);
* encryption level which cannot be selected to do that. goto out;
*/ }
if (LIST_ISEMPTY(frms) && next_qel) {
if (LIST_ISEMPTY(frms)) {
prv_pkt = cur_pkt; prv_pkt = cur_pkt;
} }
else { 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); qc_txb_store(buf, dglen, first_pkt);
/* Build only one datagram when an immediate close is required. */
if (cc)
goto out;
first_pkt = NULL; first_pkt = NULL;
dglen = 0; dglen = 0;
padding = 0; padding = 0;
prv_pkt = NULL; prv_pkt = NULL;
} }
} }
TRACE_DEVEL("next encryption level", QUIC_EV_CONN_PHPKTS, qc);
} }
if (first_pkt)
qc_txb_store(buf, dglen, first_pkt);
out: out:
if (cc && total) { if (cc && total) {
BUG_ON(buf != &qc->tx.cc_buf); BUG_ON(buf != &qc->tx.cc_buf);