public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Stefano Brivio <sbrivio@redhat.com>
To: Asahi Lina <lina@asahilina.net>
Cc: passt-dev@passt.top, Sergio Lopez <slp@redhat.com>,
	Jon Maloy <jmaloy@redhat.com>
Subject: Re: [PATCH] tcp: Add missing EPOLLET flag for established sockets
Date: Fri, 10 Jan 2025 11:28:36 +0100	[thread overview]
Message-ID: <20250110112836.50e8c63e@elisabeth> (raw)
In-Reply-To: <20241229132530.33beab46@elisabeth>

Sorry, it took a while (and I could reproduce this with muvm, too):

On Sun, 29 Dec 2024 13:25:30 +0100
Stefano Brivio <sbrivio@redhat.com> wrote:

> On Sun, 29 Dec 2024 00:31:11 +0900
> Asahi Lina <lina@asahilina.net> wrote:
> 
> > I was thinking of this, maybe the easiest solution would be to just set
> > STALLED if we get an EAGAIN *and* the current peek offset is nonzero.  
> 
> Actually, I think this is the correct solution (with "peek offset" here
> meaning the actual offset at which we peek, not the value we pass to
> SO_PEEK_OFF, see below), because it substantially restores the
> behaviour that was intended before e63d281871ef ("tcp: leverage support
> of SO_PEEK_OFF socket option when available").
> 
> That's what STALLED was for: if there's data on the socket, but we
> can't read anything more, set EPOLLET. An ACK from the guest will make
> us clear EPOLLET and have another look.
> 
> Right now, STALLED is not always set when it should. If it's cleared
> because of an ACK which doesn't acknowledge all the data pending on the
> socket, then it's broken, because of the early return on EAGAIN.
> 
> Note that we generally set SO_PEEK_OFF to 0 (and reset it on
> retransmissions, that is, whenever we need to "re-read" data), but that
> does *not* mean that the offset is zero: it means that the offset is
> "what we last peeked" (see also socket(7)).
> 
> I know, it sounds terribly confusing, but it makes SO_PEEK_OFF actually
> useful (the overhead from system calls would otherwise make it not
> worth using).
> 
> The actual peeking offset will be zero just after tcp_sock_consume(),
> without an intervening EPOLLIN, and in a particular case of
> tcp_revert_seq() (retransmission).
> 
> I'm not sure if we can ever have EAGAIN from the socket with a zero
> peeking offset. If we can, then we need to track that. If we can't,
> then what you suggest is equivalent to just setting STALLED if we get
> EAGAIN.

So, it looks like there are no paths where we would get EAGAIN with a
zero peeking offset. Setting STALLED in both tcp_buf_data_from_sock()
and tcp_vu_data_from_sock() before returning on EAGAIN actually
implements what you suggested, solves the problem, and doesn't create
new ones (at least in my tests).

About setting EPOLLET unconditionally, we also discussed this with
David Gibson in the latest development call: we could, in theory (and
he even tried in the past), because there are two cases where we return
before dequeuing all the data available from the socket (and we need a
subsequent wake-up even if no further data arrives):

- if we can't queue more data to the guest, in window. But then we can
  always rely on the guest waking us up with an ACK (or the ACK timeout
  handler, which we have)

- if we fail to write to the hypervisor (or tap device, for containers).
  It shouldn't really happen under normal circumstances, but there are
  no guarantees.

  In that case, we *should* set EPOLLOUT on that descriptor, and keep
  track of all the sockets that had pending data, and poll them once
  the guest descriptor is ready for writing, otherwise they would get
  stuck (at least until a timeout occurs, but that might be bad enough
  to break functionality).

  But we don't have this implementation, yet.

For the moment, I think we should set STALLED like you suggested (in
those two functions, before the early return). Do you want to send a
second version of the patch, or should I? I would actually be happy to
add more names to the git log. :)

> By the way, I wonder, if it's not too much effort to check: do you hit
> this without SO_PEEK_OFF (return false in tcp_probe_peek_offset_cap())?
> 
> > > Give me a few days... unless you or somebody else can look into it, of
> > > course.
> > >     
> > >> This brings CPU
> > >> usage down from around ~80% when downloading over TCP, to ~5% (use
> > >> case: passt as network transport for muvm, downloading Steam games).    
> > > 
> > > Hah, maybe that's the key to reproducing this reliably. My usage of
> > > passt with muvm at the moment is pretty much limited to SSH, DNS and
> > > short "test" transfers. I'll give that a try (large HTTP transfers?).    
> > 
> > Yeah, I think it's large parallel transfers from a fast CDN (easily
> > maxes out a gigabit internet connection). Perhaps an "optimized"
> > downloader like aria2c would work similarly? `aria2c -x4 <URL>` or
> > something like that.  
> 
> Perhaps, yes, thanks for the tip.
> 
> That's something I do quite frequently with QEMU guests (updating
> distribution packages from a mirror very close, large parallel
> transfers with iperf3, etc.), but maybe the virtio-net implementation
> in libkrun is somehow peculiar in this regard.

I could reproduce only with muvm and aria2c -x4 as you suggested, with
a long transfer, *not* local but almost: same data centre and about
~300µs RTT. More than that, and I don't see the issue, because the
guest's window is always large enough otherwise (I guess).

But yes, there's a peculiarity with muvm: the MTU is set to just 1500
bytes, whereas we typically have 65520 bytes with QEMU. With user-mode
networking, given that packetisation is (re-)done on the host, anything
less than what the guest interface supports doesn't make sense.

I'm using dhcpcd, but https://github.com/AsahiLinux/muvm/pull/111 makes
no difference (yet) because I forgot to handle the MTU there (passt
advertises 65520). For some reason, dhcpcd is also not setting the MTU.

I'll fix this there (or in a follow-up change). If I manually set 65520
bytes, by the way, I can't reproduce the issue anymore.

-- 
Stefano


      reply	other threads:[~2025-01-10 10:28 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-28 11:43 [PATCH] tcp: Add missing EPOLLET flag for established sockets Asahi Lina
2024-12-28 13:30 ` Stefano Brivio
2024-12-28 15:31   ` Asahi Lina
2024-12-29 12:25     ` Stefano Brivio
2025-01-10 10:28       ` Stefano Brivio [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250110112836.50e8c63e@elisabeth \
    --to=sbrivio@redhat.com \
    --cc=jmaloy@redhat.com \
    --cc=lina@asahilina.net \
    --cc=passt-dev@passt.top \
    --cc=slp@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).