comparison src/event/quic/ngx_event_quic.c @ 8290:faa3201ff351 quic

QUIC: improved setting the lost timer. Setting the timer is brought into compliance with quic-recovery-34. Now it's set from a single function ngx_quic_set_lost_timer() that takes into account both loss detection and PTO. The following issues are fixed with this change: - when in loss detection mode, discarding a context could turn off the timer forever after switching to the PTO mode - when in loss detection mode, sending a packet resulted in rescheduling the timer as if it's always in the PTO mode
author Roman Arutyunyan <arut@nginx.com>
date Fri, 12 Feb 2021 14:40:33 +0300
parents 88c9c868a7c9
children 9ed95726b99b
comparison
equal deleted inserted replaced
8289:88c9c868a7c9 8290:faa3201ff351
21 */ 21 */
22 #define ngx_quic_get_send_ctx(qc, level) \ 22 #define ngx_quic_get_send_ctx(qc, level) \
23 ((level) == ssl_encryption_initial) ? &((qc)->send_ctx[0]) \ 23 ((level) == ssl_encryption_initial) ? &((qc)->send_ctx[0]) \
24 : (((level) == ssl_encryption_handshake) ? &((qc)->send_ctx[1]) \ 24 : (((level) == ssl_encryption_handshake) ? &((qc)->send_ctx[1]) \
25 : &((qc)->send_ctx[2])) 25 : &((qc)->send_ctx[2]))
26
27 #define ngx_quic_lost_threshold(qc) \
28 ngx_max(NGX_QUIC_TIME_THR * ngx_max((qc)->latest_rtt, (qc)->avg_rtt), \
29 NGX_QUIC_TIME_GRANULARITY)
26 30
27 #define NGX_QUIC_SEND_CTX_LAST (NGX_QUIC_ENCRYPTION_LAST - 1) 31 #define NGX_QUIC_SEND_CTX_LAST (NGX_QUIC_ENCRYPTION_LAST - 1)
28 32
29 /* 33 /*
30 * 7.4. Cryptographic Message Buffering 34 * 7.4. Cryptographic Message Buffering
355 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt, 359 static void ngx_quic_set_packet_number(ngx_quic_header_t *pkt,
356 ngx_quic_send_ctx_t *ctx); 360 ngx_quic_send_ctx_t *ctx);
357 static void ngx_quic_pto_handler(ngx_event_t *ev); 361 static void ngx_quic_pto_handler(ngx_event_t *ev);
358 static void ngx_quic_lost_handler(ngx_event_t *ev); 362 static void ngx_quic_lost_handler(ngx_event_t *ev);
359 static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c); 363 static ngx_int_t ngx_quic_detect_lost(ngx_connection_t *c);
364 static void ngx_quic_set_lost_timer(ngx_connection_t *c);
360 static void ngx_quic_resend_frames(ngx_connection_t *c, 365 static void ngx_quic_resend_frames(ngx_connection_t *c,
361 ngx_quic_send_ctx_t *ctx); 366 ngx_quic_send_ctx_t *ctx);
362 static void ngx_quic_push_handler(ngx_event_t *ev); 367 static void ngx_quic_push_handler(ngx_event_t *ev);
363 368
364 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp, 369 static void ngx_quic_rbtree_insert_stream(ngx_rbtree_node_t *temp,
2605 if (level == ssl_encryption_initial) { 2610 if (level == ssl_encryption_initial) {
2606 ngx_quic_clear_temp_server_ids(c); 2611 ngx_quic_clear_temp_server_ids(c);
2607 } 2612 }
2608 2613
2609 ctx->send_ack = 0; 2614 ctx->send_ack = 0;
2615
2616 ngx_quic_set_lost_timer(c);
2610 } 2617 }
2611 2618
2612 2619
2613 static ngx_int_t 2620 static ngx_int_t
2614 ngx_quic_check_csid(ngx_quic_connection_t *qc, ngx_quic_header_t *pkt) 2621 ngx_quic_check_csid(ngx_quic_connection_t *qc, ngx_quic_header_t *pkt)
4917 if (!qc->send_timer_set && !qc->closing) { 4924 if (!qc->send_timer_set && !qc->closing) {
4918 qc->send_timer_set = 1; 4925 qc->send_timer_set = 1;
4919 ngx_add_timer(c->read, qc->tp.max_idle_timeout); 4926 ngx_add_timer(c->read, qc->tp.max_idle_timeout);
4920 } 4927 }
4921 } 4928 }
4929
4930 ngx_quic_set_lost_timer(c);
4922 4931
4923 return NGX_OK; 4932 return NGX_OK;
4924 } 4933 }
4925 4934
4926 4935
5165 do { 5174 do {
5166 q = ngx_queue_head(&ctx->frames); 5175 q = ngx_queue_head(&ctx->frames);
5167 ngx_queue_remove(q); 5176 ngx_queue_remove(q);
5168 ngx_queue_insert_tail(&ctx->sent, q); 5177 ngx_queue_insert_tail(&ctx->sent, q);
5169 } while (--nframes); 5178 } while (--nframes);
5170
5171 if (qc->pto.timer_set) {
5172 ngx_del_timer(&qc->pto);
5173 }
5174
5175 ngx_add_timer(&qc->pto, ngx_quic_pto(c, ctx));
5176 } 5179 }
5177 5180
5178 cg->in_flight += res.len; 5181 cg->in_flight += res.len;
5179 5182
5180 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, 5183 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
5421 5424
5422 static ngx_int_t 5425 static ngx_int_t
5423 ngx_quic_detect_lost(ngx_connection_t *c) 5426 ngx_quic_detect_lost(ngx_connection_t *c)
5424 { 5427 {
5425 ngx_uint_t i; 5428 ngx_uint_t i;
5426 ngx_msec_t now, wait, min_wait, thr; 5429 ngx_msec_t now, wait, thr;
5427 ngx_queue_t *q; 5430 ngx_queue_t *q;
5428 ngx_quic_frame_t *start; 5431 ngx_quic_frame_t *start;
5429 ngx_quic_send_ctx_t *ctx; 5432 ngx_quic_send_ctx_t *ctx;
5430 ngx_quic_connection_t *qc; 5433 ngx_quic_connection_t *qc;
5431 5434
5432 qc = ngx_quic_get_connection(c); 5435 qc = ngx_quic_get_connection(c);
5433 now = ngx_current_msec; 5436 now = ngx_current_msec;
5434 5437 thr = ngx_quic_lost_threshold(qc);
5435 min_wait = 0;
5436
5437 thr = NGX_QUIC_TIME_THR * ngx_max(qc->latest_rtt, qc->avg_rtt);
5438 thr = ngx_max(thr, NGX_QUIC_TIME_GRANULARITY);
5439 5438
5440 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { 5439 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
5441 5440
5442 ctx = &qc->send_ctx[i]; 5441 ctx = &qc->send_ctx[i];
5443 5442
5461 start->pnum, thr, (ngx_int_t) wait, start->level); 5460 start->pnum, thr, (ngx_int_t) wait, start->level);
5462 5461
5463 if ((ngx_msec_int_t) wait > 0 5462 if ((ngx_msec_int_t) wait > 0
5464 && ctx->largest_ack - start->pnum < NGX_QUIC_PKT_THR) 5463 && ctx->largest_ack - start->pnum < NGX_QUIC_PKT_THR)
5465 { 5464 {
5466
5467 if (min_wait == 0 || wait < min_wait) {
5468 min_wait = wait;
5469 }
5470
5471 break; 5465 break;
5472 } 5466 }
5473 5467
5474 ngx_quic_resend_frames(c, ctx); 5468 ngx_quic_resend_frames(c, ctx);
5475 } 5469 }
5476 } 5470 }
5477 5471
5478 /* no more preceeding packets */ 5472 ngx_quic_set_lost_timer(c);
5479 5473
5480 if (min_wait == 0) { 5474 return NGX_OK;
5481 qc->pto.handler = ngx_quic_pto_handler; 5475 }
5482 return NGX_OK; 5476
5483 } 5477
5484 5478 static void
5485 qc->pto.handler = ngx_quic_lost_handler; 5479 ngx_quic_set_lost_timer(ngx_connection_t *c)
5480 {
5481 ngx_uint_t i;
5482 ngx_msec_t now;
5483 ngx_queue_t *q;
5484 ngx_msec_int_t lost, pto, w;
5485 ngx_quic_frame_t *f;
5486 ngx_quic_send_ctx_t *ctx;
5487 ngx_quic_connection_t *qc;
5488
5489 qc = ngx_quic_get_connection(c);
5490 now = ngx_current_msec;
5491
5492 lost = -1;
5493 pto = -1;
5494
5495 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) {
5496 ctx = &qc->send_ctx[i];
5497
5498 if (ngx_queue_empty(&ctx->sent)) {
5499 continue;
5500 }
5501
5502 if (ctx->largest_ack != NGX_QUIC_UNSET_PN) {
5503 q = ngx_queue_head(&ctx->sent);
5504 f = ngx_queue_data(q, ngx_quic_frame_t, queue);
5505 w = (ngx_msec_int_t) (f->last + ngx_quic_lost_threshold(qc) - now);
5506
5507 if (f->pnum <= ctx->largest_ack) {
5508 if (w < 0 || ctx->largest_ack - f->pnum >= NGX_QUIC_PKT_THR) {
5509 w = 0;
5510 }
5511
5512 if (lost == -1 || w < lost) {
5513 lost = w;
5514 }
5515 }
5516 }
5517
5518 q = ngx_queue_last(&ctx->sent);
5519 f = ngx_queue_data(q, ngx_quic_frame_t, queue);
5520 w = (ngx_msec_int_t) (f->last + ngx_quic_pto(c, ctx) - now);
5521
5522 if (w < 0) {
5523 w = 0;
5524 }
5525
5526 if (pto == -1 || w < pto) {
5527 pto = w;
5528 }
5529 }
5486 5530
5487 if (qc->pto.timer_set) { 5531 if (qc->pto.timer_set) {
5488 ngx_del_timer(&qc->pto); 5532 ngx_del_timer(&qc->pto);
5489 } 5533 }
5490 5534
5491 ngx_add_timer(&qc->pto, min_wait); 5535 if (lost != -1) {
5492 5536 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
5493 return NGX_OK; 5537 "quic lost timer lost:%M", lost);
5538
5539 qc->pto.handler = ngx_quic_lost_handler;
5540 ngx_add_timer(&qc->pto, lost);
5541 return;
5542 }
5543
5544 if (pto != -1) {
5545 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
5546 "quic lost timer pto:%M", pto);
5547
5548 qc->pto.handler = ngx_quic_pto_handler;
5549 ngx_add_timer(&qc->pto, pto);
5550 return;
5551 }
5552
5553 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic lost timer unset");
5494 } 5554 }
5495 5555
5496 5556
5497 static void 5557 static void
5498 ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx) 5558 ngx_quic_resend_frames(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx)