# HG changeset patch # User Roman Arutyunyan # Date 1627552156 -10800 # Node ID f3331deed357be069e04dc5db909b14dc7c6dbbc # Parent ad046179eb914f4a92e01c3fa6c35b830cadbb34 QUIC: limit in-flight bytes by congestion window. Previously, in-flight byte counter and congestion window were properly maintained, but the limit was not properly implemented. Now a new datagram is sent only if in-flight byte counter is less than window. The limit is datagram-based, which means that a single datagram may lead to exceeding the limit, but the next one will not be sent. diff --git a/src/event/quic/ngx_event_quic_ack.c b/src/event/quic/ngx_event_quic_ack.c --- a/src/event/quic/ngx_event_quic_ack.c +++ b/src/event/quic/ngx_event_quic_ack.c @@ -293,6 +293,7 @@ ngx_quic_handle_ack_frame_range(ngx_conn void ngx_quic_congestion_ack(ngx_connection_t *c, ngx_quic_frame_t *f) { + ngx_uint_t blocked; ngx_msec_t timer; ngx_quic_congestion_t *cg; ngx_quic_connection_t *qc; @@ -304,6 +305,8 @@ ngx_quic_congestion_ack(ngx_connection_t qc = ngx_quic_get_connection(c); cg = &qc->congestion; + blocked = (cg->in_flight >= cg->window) ? 1 : 0; + cg->in_flight -= f->plen; timer = f->last - cg->recovery_start; @@ -313,7 +316,7 @@ ngx_quic_congestion_ack(ngx_connection_t "quic congestion ack recovery win:%uz ss:%z if:%uz", cg->window, cg->ssthresh, cg->in_flight); - return; + goto done; } if (cg->window < cg->ssthresh) { @@ -338,6 +341,12 @@ ngx_quic_congestion_ack(ngx_connection_t if ((ngx_msec_int_t) timer < 0) { cg->recovery_start = ngx_current_msec - qc->tp.max_idle_timeout * 2; } + +done: + + if (blocked && cg->in_flight < cg->window) { + ngx_post_event(&qc->push, &ngx_posted_events); + } } @@ -620,6 +629,7 @@ ngx_quic_resend_frames(ngx_connection_t static void ngx_quic_congestion_lost(ngx_connection_t *c, ngx_quic_frame_t *f) { + ngx_uint_t blocked; ngx_msec_t timer; ngx_quic_congestion_t *cg; ngx_quic_connection_t *qc; @@ -631,6 +641,8 @@ ngx_quic_congestion_lost(ngx_connection_ qc = ngx_quic_get_connection(c); cg = &qc->congestion; + blocked = (cg->in_flight >= cg->window) ? 1 : 0; + cg->in_flight -= f->plen; f->plen = 0; @@ -641,7 +653,7 @@ ngx_quic_congestion_lost(ngx_connection_ "quic congestion lost recovery win:%uz ss:%z if:%uz", cg->window, cg->ssthresh, cg->in_flight); - return; + goto done; } cg->recovery_start = ngx_current_msec; @@ -656,6 +668,12 @@ ngx_quic_congestion_lost(ngx_connection_ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic congestion lost win:%uz ss:%z if:%uz", cg->window, cg->ssthresh, cg->in_flight); + +done: + + if (blocked && cg->in_flight < cg->window) { + ngx_post_event(&qc->push, &ngx_posted_events); + } } diff --git a/src/event/quic/ngx_event_quic_output.c b/src/event/quic/ngx_event_quic_output.c --- a/src/event/quic/ngx_event_quic_output.c +++ b/src/event/quic/ngx_event_quic_output.c @@ -147,13 +147,16 @@ ngx_quic_create_datagrams(ngx_connection ngx_uint_t i, pad; ngx_quic_path_t *path; ngx_quic_send_ctx_t *ctx; + ngx_quic_congestion_t *cg; ngx_quic_connection_t *qc; static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; qc = ngx_quic_get_connection(c); + cg = &qc->congestion; path = qsock->path; - for ( ;; ) { + while (cg->in_flight < cg->window) { + p = dst; len = ngx_min(qc->ctp.max_udp_payload_size, @@ -339,10 +342,12 @@ ngx_quic_create_segments(ngx_connection_ ngx_uint_t nseg; ngx_quic_path_t *path; ngx_quic_send_ctx_t *ctx; + ngx_quic_congestion_t *cg; ngx_quic_connection_t *qc; static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF]; qc = ngx_quic_get_connection(c); + cg = &qc->congestion; path = qsock->path; ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); @@ -364,7 +369,7 @@ ngx_quic_create_segments(ngx_connection_ len = ngx_min(segsize, (size_t) (end - p)); - if (len) { + if (len && cg->in_flight < cg->window) { n = ngx_quic_output_packet(c, ctx, p, len, len, qsock); if (n == NGX_ERROR) { @@ -531,7 +536,6 @@ ngx_quic_output_packet(ngx_connection_t ngx_queue_t *q; ngx_quic_frame_t *f; ngx_quic_header_t pkt; - ngx_quic_congestion_t *cg; ngx_quic_connection_t *qc; static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; @@ -545,7 +549,6 @@ ngx_quic_output_packet(ngx_connection_t max, min); qc = ngx_quic_get_connection(c); - cg = &qc->congestion; hlen = (ctx->level == ssl_encryption_application) ? NGX_QUIC_MAX_SHORT_HEADER @@ -568,10 +571,6 @@ ngx_quic_output_packet(ngx_connection_t { f = ngx_queue_data(q, ngx_quic_frame_t, queue); - if (!pkt.need_ack && f->need_ack && max > cg->window) { - max = cg->window; - } - if (f->type == NGX_QUIC_FT_PATH_RESPONSE || f->type == NGX_QUIC_FT_PATH_CHALLENGE) {