[PATCH] Stream: don't flush empty buffers created for read errors.
Maxim Dounin
mdounin at mdounin.ru
Fri Jun 3 21:13:05 UTC 2022
Hello!
On Thu, Jun 02, 2022 at 03:20:54AM +0000, Aleksei Bavshin via nginx-devel wrote:
> > I don't think it's the way to go. Semantically, flush and
> > last_buf are mutually exclusive: last_buf implies flushing of all
> > remaining data, and there should be no flush set if last_buf is
> > set.
> >
> > The "cl->buf->flush = !src->read->eof" approach might be actually
> > better and more obvious: it simply ensures that last_buf and flush
> > are not set at the same time. I don't immediately see any cases
> > where it can break things, and this should fix the original
> > problem with empty UDP packets being sent.
>
> Thanks for confirming that, I wasn't sure it is the right approach exactly because I had doubts regarding the mutual exclusivity of the flags.
> Updated patch below; tests are passing on both branches and all systems we have in CI.
>
> # HG changeset patch
> # User Aleksei Bavshin <a.bavshin at f5.com>
> # Date 1653330584 25200
> # Mon May 23 11:29:44 2022 -0700
> # Node ID 40926829be83986a3a5a5f941d2014000a0acd2e
> # Parent e0cfab501dd11fdd23ad492419692269d3a01fc7
> 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).
>
> This happens because we mark the buffer as both 'flush' and 'last_buf', and
> ngx_stream_write_filter has special handling for flush with certain types of
> connections (see d127837c714f, 32b0ba4855a6). The flags are meant to be
> mutually exclusive, so the fix is to ensure that flush and last_buf are not set
> at the same time.
>
> 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
> @@ -1735,7 +1735,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 = !src->read->eof;
>
> (*packets)++;
> *received += n;
Looks good to me.
Roman, please take another look.
--
Maxim Dounin
http://mdounin.ru/
More information about the nginx-devel
mailing list