mirror of
https://github.com/nginx/nginx.git
synced 2025-06-12 21:52:41 +08:00
QUIC: do not block ACKs by congestion control.
Previously, it was not possible to send acknowledgments if the
congestion window was limited or temporarily exceeded, such as
after sending a large response or MTU probe. If ACKs were not
received from the peer for some reason to update the in-flight
bytes counter below the congestion window, this might result in
a stalled connection.
The fix is to send ACKs regardless of congestion control. This
meets RFC 9002, Section 7:
: Similar to TCP, packets containing only ACK frames do not count
: toward bytes in flight and are not congestion controlled.
This is a simplified implementation to send ACK frames from the
head of the queue. This was made possible after 6f5f17358
.
Reported in trac ticket #2621 and subsequently by Vladimir Homutov:
https://mailman.nginx.org/pipermail/nginx-devel/2025-April/ZKBAWRJVQXSZ2ISG3YJAF3EWMDRDHCMO.html
This commit is contained in:
parent
adda704158
commit
d6bd356e19
@ -55,7 +55,8 @@ static ssize_t ngx_quic_send_segments(ngx_connection_t *c, u_char *buf,
|
|||||||
size_t len, struct sockaddr *sockaddr, socklen_t socklen, size_t segment);
|
size_t len, struct sockaddr *sockaddr, socklen_t socklen, size_t segment);
|
||||||
#endif
|
#endif
|
||||||
static ssize_t ngx_quic_output_packet(ngx_connection_t *c,
|
static ssize_t ngx_quic_output_packet(ngx_connection_t *c,
|
||||||
ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min);
|
ngx_quic_send_ctx_t *ctx, u_char *data, size_t max, size_t min,
|
||||||
|
ngx_uint_t ack_only);
|
||||||
static void ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
|
static void ngx_quic_init_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
|
||||||
ngx_quic_header_t *pkt, ngx_quic_path_t *path);
|
ngx_quic_header_t *pkt, ngx_quic_path_t *path);
|
||||||
static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
|
static ngx_uint_t ngx_quic_get_padding_level(ngx_connection_t *c);
|
||||||
@ -131,8 +132,7 @@ ngx_quic_create_datagrams(ngx_connection_t *c)
|
|||||||
ngx_memzero(preserved_pnum, sizeof(preserved_pnum));
|
ngx_memzero(preserved_pnum, sizeof(preserved_pnum));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (cg->in_flight < cg->window) {
|
do {
|
||||||
|
|
||||||
p = dst;
|
p = dst;
|
||||||
|
|
||||||
len = ngx_quic_path_limit(c, path, path->mtu);
|
len = ngx_quic_path_limit(c, path, path->mtu);
|
||||||
@ -158,7 +158,8 @@ ngx_quic_create_datagrams(ngx_connection_t *c)
|
|||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = ngx_quic_output_packet(c, ctx, p, len, min);
|
n = ngx_quic_output_packet(c, ctx, p, len, min,
|
||||||
|
cg->in_flight >= cg->window);
|
||||||
if (n == NGX_ERROR) {
|
if (n == NGX_ERROR) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
@ -187,7 +188,8 @@ ngx_quic_create_datagrams(ngx_connection_t *c)
|
|||||||
ngx_quic_commit_send(c);
|
ngx_quic_commit_send(c);
|
||||||
|
|
||||||
path->sent += len;
|
path->sent += len;
|
||||||
}
|
|
||||||
|
} while (cg->in_flight < cg->window);
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
@ -315,6 +317,10 @@ ngx_quic_allow_segmentation(ngx_connection_t *c)
|
|||||||
|
|
||||||
bytes += f->len;
|
bytes += f->len;
|
||||||
|
|
||||||
|
if (qc->congestion.in_flight + bytes >= qc->congestion.window) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (bytes > len * 3) {
|
if (bytes > len * 3) {
|
||||||
/* require at least ~3 full packets to batch */
|
/* require at least ~3 full packets to batch */
|
||||||
return 1;
|
return 1;
|
||||||
@ -364,7 +370,7 @@ ngx_quic_create_segments(ngx_connection_t *c)
|
|||||||
|
|
||||||
if (len && cg->in_flight + (p - dst) < cg->window) {
|
if (len && cg->in_flight + (p - dst) < cg->window) {
|
||||||
|
|
||||||
n = ngx_quic_output_packet(c, ctx, p, len, len);
|
n = ngx_quic_output_packet(c, ctx, p, len, len, 0);
|
||||||
if (n == NGX_ERROR) {
|
if (n == NGX_ERROR) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
@ -521,7 +527,7 @@ ngx_quic_get_padding_level(ngx_connection_t *c)
|
|||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
|
ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
|
||||||
u_char *data, size_t max, size_t min)
|
u_char *data, size_t max, size_t min, ngx_uint_t ack_only)
|
||||||
{
|
{
|
||||||
size_t len, pad, min_payload, max_payload;
|
size_t len, pad, min_payload, max_payload;
|
||||||
u_char *p;
|
u_char *p;
|
||||||
@ -585,6 +591,10 @@ ngx_quic_output_packet(ngx_connection_t *c, ngx_quic_send_ctx_t *ctx,
|
|||||||
{
|
{
|
||||||
f = ngx_queue_data(q, ngx_quic_frame_t, queue);
|
f = ngx_queue_data(q, ngx_quic_frame_t, queue);
|
||||||
|
|
||||||
|
if (ack_only && f->type != NGX_QUIC_FT_ACK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (len >= max_payload) {
|
if (len >= max_payload) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user