MINOR: quic: improve sending API on retransmit

qc_send_hdshk_pkts() is a wrapper for qc_prep_hpkts() used on
retransmission. It was restricted to use two quic_enc_level pointers as
distinct arguments. Adapt it to directly use the same list of
quic_enc_level which is passed then to qc_prep_hpkts().

Now for retransmission quic_enc_level send list is built directly into
qc_dgrams_retransmit() which calls qc_send_hdshk_pkts().

Along this change, a new utility function qel_register_send() is
defined. It is an helper to build the quic_enc_level send list. It
enfores that each quic_enc_level instance is only registered in a single
list to prevent memory issues. It is both used in qc_dgrams_retransmit()
and quic_conn_io_cb().
This commit is contained in:
Amaury Denoyelle 2024-04-05 17:43:38 +02:00
parent 93f5b4c8ae
commit 3a8f4761e7
3 changed files with 34 additions and 36 deletions

View File

@ -33,6 +33,8 @@ void qc_txb_release(struct quic_conn *qc);
int qc_purge_txbuf(struct quic_conn *qc, struct buffer *buf);
struct buffer *qc_get_txb(struct quic_conn *qc);
void qel_register_send(struct list *send_list, struct quic_enc_level *qel,
struct list *frms);
int qc_prep_hpkts(struct quic_conn *qc, struct buffer *buf, struct list *qels);
int qc_send_ppkts(struct buffer *buf, struct ssl_sock_ctx *ctx);
int qc_send_app_pkts(struct quic_conn *qc, struct list *frms);

View File

@ -795,11 +795,8 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
}
/* Insert each QEL into sending list. */
list_for_each_entry(qel, &qc->qel_list, list) {
BUG_ON(LIST_INLIST(&qel->el_send));
LIST_APPEND(&send_list, &qel->el_send);
qel->send_frms = &qel->pktns->tx.frms;
}
list_for_each_entry(qel, &qc->qel_list, list)
qel_register_send(&send_list, qel, &qel->pktns->tx.frms);
buf = qc_get_txb(qc);
if (!buf)

View File

@ -860,12 +860,11 @@ int qc_prep_hpkts(struct quic_conn *qc, struct buffer *buf, struct list *qels)
* Returns 1 if succeeded, 0 if not.
*/
int qc_send_hdshk_pkts(struct quic_conn *qc, int old_data,
struct quic_enc_level *qel1, struct quic_enc_level *qel2)
struct list *send_list)
{
struct quic_enc_level *qel, *tmp_qel;
int ret, status = 0;
struct buffer *buf = qc_get_txb(qc);
struct list send_list = LIST_HEAD_INIT(send_list);
TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
@ -891,22 +890,7 @@ int qc_send_hdshk_pkts(struct quic_conn *qc, int old_data,
qc->flags |= QUIC_FL_CONN_RETRANS_OLD_DATA;
}
/* At least one QEL must be set or sending is unnecessary. */
BUG_ON(!qel1 && !qel2);
if (qel1) {
/* Ensure QEL is not already registered for sending. */
BUG_ON(LIST_INLIST(&qel1->el_send));
LIST_APPEND(&send_list, &qel1->el_send);
}
if (qel2) {
/* Ensure QEL is not already registered for sending. */
BUG_ON(LIST_INLIST(&qel2->el_send));
LIST_APPEND(&send_list, &qel2->el_send);
}
ret = qc_prep_hpkts(qc, buf, &send_list);
ret = qc_prep_hpkts(qc, buf, send_list);
if (ret == -1) {
qc_txb_release(qc);
TRACE_ERROR("Could not build some packets", QUIC_EV_CONN_TXPKT, qc);
@ -930,7 +914,7 @@ int qc_send_hdshk_pkts(struct quic_conn *qc, int old_data,
}
/* Always reset QEL sending list. */
list_for_each_entry_safe(qel, tmp_qel, &send_list, el_send) {
list_for_each_entry_safe(qel, tmp_qel, send_list, el_send) {
LIST_DEL_INIT(&qel->el_send);
qel->send_frms = NULL;
}
@ -939,6 +923,19 @@ int qc_send_hdshk_pkts(struct quic_conn *qc, int old_data,
return status;
}
/* Insert <qel> into <send_list> in preparation for sending. Set its send
* frames list pointer to <frms>.
*/
void qel_register_send(struct list *send_list, struct quic_enc_level *qel,
struct list *frms)
{
/* Ensure QEL is not already registered for sending. */
BUG_ON(LIST_INLIST(&qel->el_send));
LIST_APPEND(send_list, &qel->el_send);
qel->send_frms = frms;
}
/* Retransmit up to two datagrams depending on packet number space.
* Return 0 when failed, 0 if not.
*/
@ -959,9 +956,9 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
int i;
for (i = 0; i < QUIC_MAX_NB_PTO_DGRAMS; i++) {
struct list send_list = LIST_HEAD_INIT(send_list);
struct list ifrms = LIST_HEAD_INIT(ifrms);
struct list hfrms = LIST_HEAD_INIT(hfrms);
struct list qels = LIST_HEAD_INIT(qels);
qc_prep_hdshk_fast_retrans(qc, &ifrms, &hfrms);
TRACE_DEVEL("Avail. ack eliciting frames", QUIC_EV_CONN_FRMLIST, qc, &ifrms);
@ -970,24 +967,25 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
ipktns->tx.pto_probe = 1;
if (!LIST_ISEMPTY(&hfrms))
hpktns->tx.pto_probe = 1;
qc->iel->send_frms = &ifrms;
qel_register_send(&send_list, qc->iel, &ifrms);
if (qc->hel)
qc->hel->send_frms = &hfrms;
sret = qc_send_hdshk_pkts(qc, 1, qc->iel, qc->hel);
qel_register_send(&send_list, qc->hel, &hfrms);
sret = qc_send_hdshk_pkts(qc, 1, &send_list);
qc_free_frm_list(qc, &ifrms);
qc_free_frm_list(qc, &hfrms);
if (!sret)
goto leave;
}
else {
/* We are in the case where the anti-amplification limit will be
* reached after having sent this datagram or some handshake frames
* could not be allocated. There is no need to send more than one
* datagram.
/* No frame to send due to amplification limit
* or allocation failure. A PING frame will be
* emitted for probing.
*/
ipktns->tx.pto_probe = 1;
qc->iel->send_frms = &ifrms;
sret = qc_send_hdshk_pkts(qc, 0, qc->iel, NULL);
qel_register_send(&send_list, qc->iel, &ifrms);
sret = qc_send_hdshk_pkts(qc, 0, &send_list);
qc_free_frm_list(qc, &ifrms);
qc_free_frm_list(qc, &hfrms);
if (!sret)
@ -1008,14 +1006,15 @@ int qc_dgrams_retransmit(struct quic_conn *qc)
if (hpktns && (hpktns->flags & QUIC_FL_PKTNS_PROBE_NEEDED)) {
hpktns->tx.pto_probe = 0;
for (i = 0; i < QUIC_MAX_NB_PTO_DGRAMS; i++) {
struct list send_list = LIST_HEAD_INIT(send_list);
struct list frms1 = LIST_HEAD_INIT(frms1);
qc_prep_fast_retrans(qc, hpktns, &frms1, NULL);
TRACE_DEVEL("Avail. ack eliciting frames", QUIC_EV_CONN_FRMLIST, qc, &frms1);
if (!LIST_ISEMPTY(&frms1)) {
hpktns->tx.pto_probe = 1;
qc->hel->send_frms = &frms1;
sret = qc_send_hdshk_pkts(qc, 1, qc->hel, NULL);
qel_register_send(&send_list, qc->hel, &frms1);
sret = qc_send_hdshk_pkts(qc, 1, &send_list);
qc_free_frm_list(qc, &frms1);
if (!sret)
goto leave;