diff --git a/include/haproxy/quic_loss.h b/include/haproxy/quic_loss.h index de22ed28b..1f63e30d4 100644 --- a/include/haproxy/quic_loss.h +++ b/include/haproxy/quic_loss.h @@ -81,5 +81,7 @@ struct quic_pktns *quic_pto_pktns(struct quic_conn *qc, int handshake_completed, unsigned int *pto); +void qc_packet_loss_lookup(struct quic_pktns *pktns, struct quic_conn *qc, + struct list *lost_pkts); #endif /* USE_QUIC */ #endif /* _PROTO_QUIC_LOSS_H */ diff --git a/src/quic_loss.c b/src/quic_loss.c index 2f6643c7c..b7f607524 100644 --- a/src/quic_loss.c +++ b/src/quic_loss.c @@ -1,3 +1,5 @@ +#include + #include #include @@ -127,3 +129,61 @@ struct quic_pktns *quic_pto_pktns(struct quic_conn *qc, return pktns; } + +/* Look for packet loss from sent packets for encryption level of a + * connection with as I/O handler context. If remove is true, remove them from + * their tree if deemed as lost or set the value the packet number + * space if any not deemed lost. + * Should be called after having received an ACK frame with newly acknowledged + * packets or when the the loss detection timer has expired. + * Always succeeds. + */ +void qc_packet_loss_lookup(struct quic_pktns *pktns, struct quic_conn *qc, + struct list *lost_pkts) +{ + struct eb_root *pkts; + struct eb64_node *node; + struct quic_loss *ql; + unsigned int loss_delay; + + TRACE_ENTER(QUIC_EV_CONN_PKTLOSS, qc, pktns); + pkts = &pktns->tx.pkts; + pktns->tx.loss_time = TICK_ETERNITY; + if (eb_is_empty(pkts)) + goto out; + + ql = &qc->path->loss; + loss_delay = QUIC_MAX(ql->latest_rtt, ql->srtt >> 3); + loss_delay = QUIC_MAX(loss_delay, MS_TO_TICKS(QUIC_TIMER_GRANULARITY)); + + node = eb64_first(pkts); + while (node) { + struct quic_tx_packet *pkt; + int64_t largest_acked_pn; + unsigned int loss_time_limit, time_sent; + + pkt = eb64_entry(&node->node, struct quic_tx_packet, pn_node); + largest_acked_pn = pktns->rx.largest_acked_pn; + node = eb64_next(node); + if ((int64_t)pkt->pn_node.key > largest_acked_pn) + break; + + time_sent = pkt->time_sent; + loss_time_limit = tick_add(time_sent, loss_delay); + if (tick_is_le(time_sent, now_ms) || + (int64_t)largest_acked_pn >= pkt->pn_node.key + QUIC_LOSS_PACKET_THRESHOLD) { + eb64_delete(&pkt->pn_node); + LIST_APPEND(lost_pkts, &pkt->list); + } + else { + if (tick_isset(pktns->tx.loss_time)) + pktns->tx.loss_time = tick_first(pktns->tx.loss_time, loss_time_limit); + else + pktns->tx.loss_time = loss_time_limit; + } + } + + out: + TRACE_LEAVE(QUIC_EV_CONN_PKTLOSS, qc, pktns, lost_pkts); +} + diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 4c316a37f..778f1971c 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -1906,64 +1906,6 @@ static inline void qc_release_lost_pkts(struct quic_conn *qc, } } -/* Look for packet loss from sent packets for encryption level of a - * connection with as I/O handler context. If remove is true, remove them from - * their tree if deemed as lost or set the value the packet number - * space if any not deemed lost. - * Should be called after having received an ACK frame with newly acknowledged - * packets or when the the loss detection timer has expired. - * Always succeeds. - */ -static void qc_packet_loss_lookup(struct quic_pktns *pktns, - struct quic_conn *qc, - struct list *lost_pkts) -{ - struct eb_root *pkts; - struct eb64_node *node; - struct quic_loss *ql; - unsigned int loss_delay; - - TRACE_ENTER(QUIC_EV_CONN_PKTLOSS, qc, pktns); - pkts = &pktns->tx.pkts; - pktns->tx.loss_time = TICK_ETERNITY; - if (eb_is_empty(pkts)) - goto out; - - ql = &qc->path->loss; - loss_delay = QUIC_MAX(ql->latest_rtt, ql->srtt >> 3); - loss_delay = QUIC_MAX(loss_delay, MS_TO_TICKS(QUIC_TIMER_GRANULARITY)); - - node = eb64_first(pkts); - while (node) { - struct quic_tx_packet *pkt; - int64_t largest_acked_pn; - unsigned int loss_time_limit, time_sent; - - pkt = eb64_entry(&node->node, struct quic_tx_packet, pn_node); - largest_acked_pn = pktns->rx.largest_acked_pn; - node = eb64_next(node); - if ((int64_t)pkt->pn_node.key > largest_acked_pn) - break; - - time_sent = pkt->time_sent; - loss_time_limit = tick_add(time_sent, loss_delay); - if (tick_is_le(time_sent, now_ms) || - (int64_t)largest_acked_pn >= pkt->pn_node.key + QUIC_LOSS_PACKET_THRESHOLD) { - eb64_delete(&pkt->pn_node); - LIST_APPEND(lost_pkts, &pkt->list); - } - else { - if (tick_isset(pktns->tx.loss_time)) - pktns->tx.loss_time = tick_first(pktns->tx.loss_time, loss_time_limit); - else - pktns->tx.loss_time = loss_time_limit; - } - } - - out: - TRACE_LEAVE(QUIC_EV_CONN_PKTLOSS, qc, pktns, lost_pkts); -} - /* 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