]> git.kaiwu.me - nginx.git/commitdiff
QUIC: fixed probe-congestion deadlock.
authorRoman Arutyunyan <arut@nginx.com>
Mon, 14 Aug 2023 04:28:30 +0000 (08:28 +0400)
committerRoman Arutyunyan <arut@nginx.com>
Mon, 14 Aug 2023 04:28:30 +0000 (08:28 +0400)
When probe timeout expired while congestion window was exhausted, probe PINGs
could not be sent.  As a result, lost packets could not be declared lost and
congestion window could not be freed for new packets.  This deadlock
continued until connection idle timeout expiration.

Now PINGs are sent separately from the frame queue without congestion control,
as specified by RFC 9002, Section 7:

  An endpoint MUST NOT send a packet if it would cause bytes_in_flight
  (see Appendix B.2) to be larger than the congestion window, unless the
  packet is sent on a PTO timer expiration (see Section 6.2) or when entering
  recovery (see Section 7.3.2).

src/event/quic/ngx_event_quic_ack.c
src/event/quic/ngx_event_quic_output.c
src/event/quic/ngx_event_quic_transport.h

index 04fc6676018d57c2f446f1a9bd9f431b8c0c3b82..182246568fc5f1199d585f5f8277380badcf0743 100644 (file)
@@ -820,9 +820,9 @@ ngx_quic_pto_handler(ngx_event_t *ev)
 {
     ngx_uint_t              i;
     ngx_msec_t              now;
-    ngx_queue_t            *q, *next;
+    ngx_queue_t            *q;
     ngx_connection_t       *c;
-    ngx_quic_frame_t       *f;
+    ngx_quic_frame_t       *f, frame;
     ngx_quic_send_ctx_t    *ctx;
     ngx_quic_connection_t  *qc;
 
@@ -859,63 +859,23 @@ ngx_quic_pto_handler(ngx_event_t *ev)
                        "quic pto %s pto_count:%ui",
                        ngx_quic_level_name(ctx->level), qc->pto_count);
 
-        for (q = ngx_queue_head(&ctx->frames);
-             q != ngx_queue_sentinel(&ctx->frames);
-             /* void */)
-        {
-            next = ngx_queue_next(q);
-            f = ngx_queue_data(q, ngx_quic_frame_t, queue);
-
-            if (f->type == NGX_QUIC_FT_PING) {
-                ngx_queue_remove(q);
-                ngx_quic_free_frame(c, f);
-            }
+        ngx_memzero(&frame, sizeof(ngx_quic_frame_t));
 
-            q = next;
-        }
+        frame.level = ctx->level;
+        frame.type = NGX_QUIC_FT_PING;
 
-        for (q = ngx_queue_head(&ctx->sent);
-             q != ngx_queue_sentinel(&ctx->sent);
-             /* void */)
+        if (ngx_quic_frame_sendto(c, &frame, 0, qc->path) != NGX_OK
+            || ngx_quic_frame_sendto(c, &frame, 0, qc->path) != NGX_OK)
         {
-            next = ngx_queue_next(q);
-            f = ngx_queue_data(q, ngx_quic_frame_t, queue);
-
-            if (f->type == NGX_QUIC_FT_PING) {
-                ngx_quic_congestion_lost(c, f);
-                ngx_queue_remove(q);
-                ngx_quic_free_frame(c, f);
-            }
-
-            q = next;
-        }
-
-        /* enforce 2 udp datagrams */
-
-        f = ngx_quic_alloc_frame(c);
-        if (f == NULL) {
-            break;
-        }
-
-        f->level = ctx->level;
-        f->type = NGX_QUIC_FT_PING;
-        f->flush = 1;
-
-        ngx_quic_queue_frame(qc, f);
-
-        f = ngx_quic_alloc_frame(c);
-        if (f == NULL) {
-            break;
+            ngx_quic_close_connection(c, NGX_ERROR);
+            return;
         }
-
-        f->level = ctx->level;
-        f->type = NGX_QUIC_FT_PING;
-
-        ngx_quic_queue_frame(qc, f);
     }
 
     qc->pto_count++;
 
+    ngx_quic_set_lost_timer(c);
+
     ngx_quic_connstate_dbg(c);
 }
 
index 37de44c749e2ce49d3548838eef16607c85b46d8..ecd5c2cef4618a8e3445a94b7c6796756b6fc5bf 100644 (file)
@@ -631,10 +631,6 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
         f->plen = 0;
 
         nframes++;
-
-        if (f->flush) {
-            break;
-        }
     }
 
     if (nframes == 0) {
index 16d9095efca6d7cf80c6b0b5f3bc8bf4cb12fdbd..02e44650bec356c103896640dd9210a4d2dea6b8 100644 (file)
@@ -271,7 +271,6 @@ struct ngx_quic_frame_s {
     ssize_t                                     len;
     unsigned                                    need_ack:1;
     unsigned                                    pkt_need_ack:1;
-    unsigned                                    flush:1;
 
     ngx_chain_t                                *data;
     union {