comparison src/event/quic/ngx_event_quic_output.c @ 8823:f3331deed357 quic

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.
author Roman Arutyunyan <arut@nginx.com>
date Thu, 29 Jul 2021 12:49:16 +0300
parents ad046179eb91
children c5155a0cb12f
comparison
equal deleted inserted replaced
8822:ad046179eb91 8823:f3331deed357
145 u_char *p; 145 u_char *p;
146 uint64_t preserved_pnum[NGX_QUIC_SEND_CTX_LAST]; 146 uint64_t preserved_pnum[NGX_QUIC_SEND_CTX_LAST];
147 ngx_uint_t i, pad; 147 ngx_uint_t i, pad;
148 ngx_quic_path_t *path; 148 ngx_quic_path_t *path;
149 ngx_quic_send_ctx_t *ctx; 149 ngx_quic_send_ctx_t *ctx;
150 ngx_quic_congestion_t *cg;
150 ngx_quic_connection_t *qc; 151 ngx_quic_connection_t *qc;
151 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; 152 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
152 153
153 qc = ngx_quic_get_connection(c); 154 qc = ngx_quic_get_connection(c);
155 cg = &qc->congestion;
154 path = qsock->path; 156 path = qsock->path;
155 157
156 for ( ;; ) { 158 while (cg->in_flight < cg->window) {
159
157 p = dst; 160 p = dst;
158 161
159 len = ngx_min(qc->ctp.max_udp_payload_size, 162 len = ngx_min(qc->ctp.max_udp_payload_size,
160 NGX_QUIC_MAX_UDP_PAYLOAD_SIZE); 163 NGX_QUIC_MAX_UDP_PAYLOAD_SIZE);
161 164
337 u_char *p, *end; 340 u_char *p, *end;
338 uint64_t preserved_pnum; 341 uint64_t preserved_pnum;
339 ngx_uint_t nseg; 342 ngx_uint_t nseg;
340 ngx_quic_path_t *path; 343 ngx_quic_path_t *path;
341 ngx_quic_send_ctx_t *ctx; 344 ngx_quic_send_ctx_t *ctx;
345 ngx_quic_congestion_t *cg;
342 ngx_quic_connection_t *qc; 346 ngx_quic_connection_t *qc;
343 static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF]; 347 static u_char dst[NGX_QUIC_MAX_UDP_SEGMENT_BUF];
344 348
345 qc = ngx_quic_get_connection(c); 349 qc = ngx_quic_get_connection(c);
350 cg = &qc->congestion;
346 path = qsock->path; 351 path = qsock->path;
347 352
348 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application); 353 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_application);
349 354
350 if (ngx_quic_generate_ack(c, ctx) != NGX_OK) { 355 if (ngx_quic_generate_ack(c, ctx) != NGX_OK) {
362 367
363 for ( ;; ) { 368 for ( ;; ) {
364 369
365 len = ngx_min(segsize, (size_t) (end - p)); 370 len = ngx_min(segsize, (size_t) (end - p));
366 371
367 if (len) { 372 if (len && cg->in_flight < cg->window) {
368 373
369 n = ngx_quic_output_packet(c, ctx, p, len, len, qsock); 374 n = ngx_quic_output_packet(c, ctx, p, len, len, qsock);
370 if (n == NGX_ERROR) { 375 if (n == NGX_ERROR) {
371 return NGX_ERROR; 376 return NGX_ERROR;
372 } 377 }
529 ngx_uint_t nframes, has_pr; 534 ngx_uint_t nframes, has_pr;
530 ngx_msec_t now; 535 ngx_msec_t now;
531 ngx_queue_t *q; 536 ngx_queue_t *q;
532 ngx_quic_frame_t *f; 537 ngx_quic_frame_t *f;
533 ngx_quic_header_t pkt; 538 ngx_quic_header_t pkt;
534 ngx_quic_congestion_t *cg;
535 ngx_quic_connection_t *qc; 539 ngx_quic_connection_t *qc;
536 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; 540 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
537 541
538 if (ngx_queue_empty(&ctx->frames)) { 542 if (ngx_queue_empty(&ctx->frames)) {
539 return 0; 543 return 0;
543 "quic output sock #%uL %s packet max:%uz min:%uz", 547 "quic output sock #%uL %s packet max:%uz min:%uz",
544 qsock->sid.seqnum, ngx_quic_level_name(ctx->level), 548 qsock->sid.seqnum, ngx_quic_level_name(ctx->level),
545 max, min); 549 max, min);
546 550
547 qc = ngx_quic_get_connection(c); 551 qc = ngx_quic_get_connection(c);
548 cg = &qc->congestion;
549 552
550 hlen = (ctx->level == ssl_encryption_application) 553 hlen = (ctx->level == ssl_encryption_application)
551 ? NGX_QUIC_MAX_SHORT_HEADER 554 ? NGX_QUIC_MAX_SHORT_HEADER
552 : NGX_QUIC_MAX_LONG_HEADER; 555 : NGX_QUIC_MAX_LONG_HEADER;
553 556
565 for (q = ngx_queue_head(&ctx->frames); 568 for (q = ngx_queue_head(&ctx->frames);
566 q != ngx_queue_sentinel(&ctx->frames); 569 q != ngx_queue_sentinel(&ctx->frames);
567 q = ngx_queue_next(q)) 570 q = ngx_queue_next(q))
568 { 571 {
569 f = ngx_queue_data(q, ngx_quic_frame_t, queue); 572 f = ngx_queue_data(q, ngx_quic_frame_t, queue);
570
571 if (!pkt.need_ack && f->need_ack && max > cg->window) {
572 max = cg->window;
573 }
574 573
575 if (f->type == NGX_QUIC_FT_PATH_RESPONSE 574 if (f->type == NGX_QUIC_FT_PATH_RESPONSE
576 || f->type == NGX_QUIC_FT_PATH_CHALLENGE) 575 || f->type == NGX_QUIC_FT_PATH_CHALLENGE)
577 { 576 {
578 has_pr = 1; 577 has_pr = 1;