[PATCH] Stream: don't flush empty buffers created for read errors.

Roman Arutyunyan arut at nginx.com
Thu May 26 09:33:57 UTC 2022


On Tue, May 24, 2022 at 04:37:11PM +0000, Aleksei Bavshin via nginx-devel wrote:
> In all honesty, the main motivation for the patch is to address a regression in UDP healthchecks caused by the behavior described below. It's already covered by tests, but the corresponding cases were disabled by default.
> 
> I considered
>     cl->buf->flush = !src->read->error;
> or even
>     cl->buf->flush = !src->read->eof; 
> but neither of those are exactly equivalent to the code below (with the latter having significantly different behavior), and IMO it would look less obvious. 
> 
> # HG changeset patch
> # User Aleksei Bavshin <a.bavshin at f5.com>
> # Date 1653330584 25200
> #      Mon May 23 11:29:44 2022 -0700
> # Branch se
> # Node ID 5a98e9cb437f7719afa2bde62de68e174fd8e03e
> # Parent  8902674cc7fe759cada415c10340f31ae4a90fba
> Stream: don't flush empty buffers created for read errors.
> 
> When we generate the last_buf buffer for an UDP upstream recv error, it does
> not contain any data from the wire. ngx_stream_write_filter attempts to forward
> it anyways, which is incorrect (e.g., UDP upstream ECONNREFUSED will be
> translated to an empty packet).
> 
> Reproduction:
> 
> stream {
>     upstream unreachable {
>         server     127.0.0.1:8880;
>     }
>     server {
>         listen     127.0.0.1:8998 udp;
>         proxy_pass unreachable;
>     }
> }
> 
> 1 0.000000000    127.0.0.1 → 127.0.0.1    UDP 47 45588 → 8998 Len=5
> 2 0.000166300    127.0.0.1 → 127.0.0.1    UDP 47 51149 → 8880 Len=5
> 3 0.000172600    127.0.0.1 → 127.0.0.1    ICMP 75 Destination unreachable (Port
> unreachable)
> 4 0.000202400    127.0.0.1 → 127.0.0.1    UDP 42 8998 → 45588 Len=0
> 
> Fixes d127837c714f.
> 
> diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
> --- a/src/stream/ngx_stream_proxy_module.c
> +++ b/src/stream/ngx_stream_proxy_module.c
> @@ -1676,7 +1676,7 @@ ngx_stream_proxy_process(ngx_stream_sess
>      ssize_t                       n;
>      ngx_buf_t                    *b;
>      ngx_int_t                     rc;
> -    ngx_uint_t                    flags, *packets;
> +    ngx_uint_t                    flags, flush, *packets;
>      ngx_msec_t                    delay;
>      ngx_chain_t                  *cl, **ll, **out, **busy;
>      ngx_connection_t             *c, *pc, *src, *dst;
> @@ -1803,9 +1803,12 @@ ngx_stream_proxy_process(ngx_stream_sess
>                  break;
>              }
>  
> +            flush = 1;
> +
>              if (n == NGX_ERROR) {
>                  src->read->eof = 1;
>                  n = 0;
> +                flush = 0;
>              }
>  
>              if (n >= 0) {
> @@ -1846,7 +1849,7 @@ ngx_stream_proxy_process(ngx_stream_sess
>  
>                  cl->buf->temporary = (n ? 1 : 0);
>                  cl->buf->last_buf = src->read->eof;
> -                cl->buf->flush = 1;
> +                cl->buf->flush = flush;
>  
>                  (*packets)++;
>                  *received += n;
> _______________________________________________
> nginx-devel mailing list -- nginx-devel at nginx.org
> To unsubscribe send an email to nginx-devel-leave at nginx.org

Looks good



More information about the nginx-devel mailing list