From: Frédéric Lécaille Date: Mon, 27 Nov 2023 15:25:53 +0000 (+0100) Subject: REORG: quic: Rename some functions used upon ACK receipt X-Git-Tag: v2.9-dev12~62 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f32fc26b620f8c78fe4c9dcbf2c7f2eebdab49ec;p=thirdparty%2Fhaproxy.git REORG: quic: Rename some functions used upon ACK receipt Rename some functions to reflect more their jobs. Move qc_release_lost_pkts() to quic_loss.c --- diff --git a/include/haproxy/quic_loss.h b/include/haproxy/quic_loss.h index 9f0b085474..d2a0e776ba 100644 --- a/include/haproxy/quic_loss.h +++ b/include/haproxy/quic_loss.h @@ -85,5 +85,7 @@ struct quic_pktns *quic_pto_pktns(struct quic_conn *qc, void qc_packet_loss_lookup(struct quic_pktns *pktns, struct quic_conn *qc, struct list *lost_pkts); +int qc_release_lost_pkts(struct quic_conn *qc, struct quic_pktns *pktns, + struct list *pkts, uint64_t now_us); #endif /* USE_QUIC */ #endif /* _PROTO_QUIC_LOSS_H */ diff --git a/include/haproxy/quic_rx.h b/include/haproxy/quic_rx.h index 8c017724e3..4cde1ad9d2 100644 --- a/include/haproxy/quic_rx.h +++ b/include/haproxy/quic_rx.h @@ -31,10 +31,11 @@ int qc_treat_rx_pkts(struct quic_conn *qc); int qc_parse_hd_form(struct quic_rx_packet *pkt, unsigned char **pos, const unsigned char *end); void quic_free_ncbuf(struct ncbuf *ncbuf); -int qc_release_lost_pkts(struct quic_conn *qc, struct quic_pktns *pktns, - struct list *pkts, uint64_t now_us); int qc_treat_rx_crypto_frms(struct quic_conn *qc, struct quic_enc_level *el, struct ssl_sock_ctx *ctx); +int qc_handle_frms_of_lost_pkt(struct quic_conn *qc, + struct quic_tx_packet *pkt, + struct list *pktns_frm_list); /* Increment the reference counter of */ static inline void quic_rx_packet_refinc(struct quic_rx_packet *pkt) diff --git a/src/quic_loss.c b/src/quic_loss.c index 0eab03d429..7d47b6af04 100644 --- a/src/quic_loss.c +++ b/src/quic_loss.c @@ -204,3 +204,82 @@ void qc_packet_loss_lookup(struct quic_pktns *pktns, struct quic_conn *qc, TRACE_LEAVE(QUIC_EV_CONN_PKTLOSS, qc); } +/* Handle list of lost packets detected at handling their TX + * frames. Send a packet loss event to the congestion controller if in flight + * packet have been lost. Also frees the packet in list. + * + * Returns 1 on success else 0 if loss limit has been exceeded. A + * CONNECTION_CLOSE was prepared to close the connection ASAP. + */ +int qc_release_lost_pkts(struct quic_conn *qc, struct quic_pktns *pktns, + struct list *pkts, uint64_t now_us) +{ + struct quic_tx_packet *pkt, *tmp, *oldest_lost, *newest_lost; + int close = 0; + + TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); + + if (LIST_ISEMPTY(pkts)) + goto leave; + + oldest_lost = newest_lost = NULL; + list_for_each_entry_safe(pkt, tmp, pkts, list) { + struct list tmp = LIST_HEAD_INIT(tmp); + + pkt->pktns->tx.in_flight -= pkt->in_flight_len; + qc->path->prep_in_flight -= pkt->in_flight_len; + qc->path->in_flight -= pkt->in_flight_len; + if (pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING) + qc->path->ifae_pkts--; + /* Treat the frames of this lost packet. */ + if (!qc_handle_frms_of_lost_pkt(qc, pkt, &pktns->tx.frms)) + close = 1; + LIST_DELETE(&pkt->list); + if (!oldest_lost) { + oldest_lost = newest_lost = pkt; + } + else { + if (newest_lost != oldest_lost) + quic_tx_packet_refdec(newest_lost); + newest_lost = pkt; + } + } + + if (!close) { + if (newest_lost) { + /* Sent a congestion event to the controller */ + struct quic_cc_event ev = { }; + + ev.type = QUIC_CC_EVT_LOSS; + ev.loss.time_sent = newest_lost->time_sent; + + quic_cc_event(&qc->path->cc, &ev); + } + + /* If an RTT have been already sampled, has been set. + * We must check if we are experiencing a persistent congestion. + * If this is the case, the congestion controller must re-enter + * slow start state. + */ + if (qc->path->loss.rtt_min && newest_lost != oldest_lost) { + unsigned int period = newest_lost->time_sent - oldest_lost->time_sent; + + if (quic_loss_persistent_congestion(&qc->path->loss, period, + now_ms, qc->max_ack_delay)) + qc->path->cc.algo->slow_start(&qc->path->cc); + } + } + + /* cannot be NULL at this stage because we have ensured + * that list is not empty. Without this, GCC 12.2.0 reports a + * possible overflow on a 0 byte region with O2 optimization. + */ + ALREADY_CHECKED(oldest_lost); + quic_tx_packet_refdec(oldest_lost); + if (newest_lost != oldest_lost) + quic_tx_packet_refdec(newest_lost); + + leave: + TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); + return !close; +} diff --git a/src/quic_rx.c b/src/quic_rx.c index 5bb130160f..9957550120 100644 --- a/src/quic_rx.c +++ b/src/quic_rx.c @@ -252,8 +252,11 @@ static int quic_stream_try_to_consume(struct quic_conn *qc, return ret; } -/* Treat frame whose packet it is attached to has just been acknowledged. */ -static void qc_treat_acked_tx_frm(struct quic_conn *qc, struct quic_frame *frm) +/* Handle frame whose packet it is attached to has just been acknowledged. The memory allocated + * for this frame will be at least released in every cases. + * Never fail. + */ +static void qc_handle_newly_acked_frm(struct quic_conn *qc, struct quic_frame *frm) { TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); TRACE_PROTO("RX ack TX frm", QUIC_EV_CONN_PRSAFRM, qc, frm); @@ -351,12 +354,9 @@ static void qc_newly_acked_pkts(struct quic_conn *qc, struct eb_root *pkts, TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); } -/* Remove down to node entries from tree of TX packet, - * deallocating them, and their TX frames. - * May be NULL if node could not be found. - */ -static void qc_ackrng_pkts(struct quic_conn *qc, - unsigned int *pkt_flags, struct list *newly_acked_pkts) +/* Handle list of newly acknowledged TX packets */ +static void qc_handle_newly_acked_pkts(struct quic_conn *qc, + unsigned int *pkt_flags, struct list *newly_acked_pkts) { struct quic_tx_packet *pkt, *tmp; @@ -368,7 +368,7 @@ static void qc_ackrng_pkts(struct quic_conn *qc, *pkt_flags |= pkt->flags; TRACE_DEVEL("Removing packet #", QUIC_EV_CONN_PRSAFRM, qc, NULL, &pkt->pn_node.key); list_for_each_entry_safe(frm, frmbak, &pkt->frms, list) - qc_treat_acked_tx_frm(qc, frm); + qc_handle_newly_acked_frm(qc, frm); /* If there are others packet in the same datagram is attached to, * detach the previous one and the next one from . */ @@ -380,16 +380,16 @@ static void qc_ackrng_pkts(struct quic_conn *qc, TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); } -/* Remove all frames from and reinsert them in the same order +/* Handle all frames sent from packet and reinsert them in the same order * they have been sent into . The loss counter of each frame is * incremented and checked if it does not exceed retransmission limit. * * Returns 1 on success, 0 if a frame loss limit is exceeded. A * CONNECTION_CLOSE is scheduled in this case. */ -static int qc_requeue_nacked_pkt_tx_frms(struct quic_conn *qc, - struct quic_tx_packet *pkt, - struct list *pktns_frm_list) +int qc_handle_frms_of_lost_pkt(struct quic_conn *qc, + struct quic_tx_packet *pkt, + struct list *pktns_frm_list) { struct quic_frame *frm, *frmbak; struct list *pkt_frm_list = &pkt->frms; @@ -482,8 +482,8 @@ static int qc_requeue_nacked_pkt_tx_frms(struct quic_conn *qc, * list and free them. * Always succeeds. */ -static void qc_treat_newly_acked_pkts(struct quic_conn *qc, - struct list *newly_acked_pkts) +static void qc_notify_cc_of_newly_acked_pkts(struct quic_conn *qc, + struct list *newly_acked_pkts) { struct quic_tx_packet *pkt, *tmp; struct quic_cc_event ev = { .type = QUIC_CC_EVT_ACK, }; @@ -513,86 +513,6 @@ static void qc_treat_newly_acked_pkts(struct quic_conn *qc, } -/* Handle list of lost packets detected at handling their TX - * frames. Send a packet loss event to the congestion controller if in flight - * packet have been lost. Also frees the packet in list. - * - * Returns 1 on success else 0 if loss limit has been exceeded. A - * CONNECTION_CLOSE was prepared to close the connection ASAP. - */ -int qc_release_lost_pkts(struct quic_conn *qc, struct quic_pktns *pktns, - struct list *pkts, uint64_t now_us) -{ - struct quic_tx_packet *pkt, *tmp, *oldest_lost, *newest_lost; - int close = 0; - - TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc); - - if (LIST_ISEMPTY(pkts)) - goto leave; - - oldest_lost = newest_lost = NULL; - list_for_each_entry_safe(pkt, tmp, pkts, list) { - struct list tmp = LIST_HEAD_INIT(tmp); - - pkt->pktns->tx.in_flight -= pkt->in_flight_len; - qc->path->prep_in_flight -= pkt->in_flight_len; - qc->path->in_flight -= pkt->in_flight_len; - if (pkt->flags & QUIC_FL_TX_PACKET_ACK_ELICITING) - qc->path->ifae_pkts--; - /* Treat the frames of this lost packet. */ - if (!qc_requeue_nacked_pkt_tx_frms(qc, pkt, &pktns->tx.frms)) - close = 1; - LIST_DELETE(&pkt->list); - if (!oldest_lost) { - oldest_lost = newest_lost = pkt; - } - else { - if (newest_lost != oldest_lost) - quic_tx_packet_refdec(newest_lost); - newest_lost = pkt; - } - } - - if (!close) { - if (newest_lost) { - /* Sent a congestion event to the controller */ - struct quic_cc_event ev = { }; - - ev.type = QUIC_CC_EVT_LOSS; - ev.loss.time_sent = newest_lost->time_sent; - - quic_cc_event(&qc->path->cc, &ev); - } - - /* If an RTT have been already sampled, has been set. - * We must check if we are experiencing a persistent congestion. - * If this is the case, the congestion controller must re-enter - * slow start state. - */ - if (qc->path->loss.rtt_min && newest_lost != oldest_lost) { - unsigned int period = newest_lost->time_sent - oldest_lost->time_sent; - - if (quic_loss_persistent_congestion(&qc->path->loss, period, - now_ms, qc->max_ack_delay)) - qc->path->cc.algo->slow_start(&qc->path->cc); - } - } - - /* cannot be NULL at this stage because we have ensured - * that list is not empty. Without this, GCC 12.2.0 reports a - * possible overflow on a 0 byte region with O2 optimization. - */ - ALREADY_CHECKED(oldest_lost); - quic_tx_packet_refdec(oldest_lost); - if (newest_lost != oldest_lost) - quic_tx_packet_refdec(newest_lost); - - leave: - TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc); - return !close; -} - /* Parse ACK frame into from a buffer at address with being at * one byte past the end of this buffer. Also update if needed, i.e. * if the largest acked packet was newly acked and if there was at least one newly @@ -692,7 +612,7 @@ static int qc_parse_ack_frm(struct quic_conn *qc, } while (1); if (!LIST_ISEMPTY(&newly_acked_pkts)) { - qc_ackrng_pkts(qc, &pkt_flags, &newly_acked_pkts); + qc_handle_newly_acked_pkts(qc, &pkt_flags, &newly_acked_pkts); if (new_largest_acked_pn && (pkt_flags & QUIC_FL_TX_PACKET_ACK_ELICITING)) { *rtt_sample = tick_remain(time_sent, now_ms); qel->pktns->rx.largest_acked_pn = ack_frm->largest_ack; @@ -703,7 +623,7 @@ static int qc_parse_ack_frm(struct quic_conn *qc, if (!qc_release_lost_pkts(qc, qel->pktns, &lost_pkts, now_ms)) goto leave; } - qc_treat_newly_acked_pkts(qc, &newly_acked_pkts); + qc_notify_cc_of_newly_acked_pkts(qc, &newly_acked_pkts); if (quic_peer_validated_addr(qc)) qc->path->loss.pto_count = 0; qc_set_timer(qc);