On Tue, Sep 17, 2024 at 12:03:13PM +0200, Laurent Vivier wrote:On 16/09/2024 09:00, David Gibson wrote:Oh, ok. IIUC you're saying that both this path and the "main" path go through vu_send(), in which case this is fine. -- David Gibson (he or they) | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you, not the other way | around. http://www.ozlabs.org/~dgibsonI tried but it's over complicated to take in input an iovec array and to use another iovec array (provided by the guest) to send data. It's easier to have a buffer and to copy it to the iovec array buffers of the guest. Moreover we don't need to have a tap_send_frames_vu() (see vu_handle_tx()), so we will introduce it to always send an iovec array with only one entry.--- a/tap.c +++ b/tap.c @@ -58,6 +58,7 @@ #include "packet.h" #include "tap.h" #include "log.h" +#include "vhost_user.h" /* IPv4 (plus ARP) and IPv6 message batches from tap/guest to IP handlers */ static PACKET_POOL_NOINIT(pool_tap4, TAP_MSGS, pkt_buf); @@ -78,16 +79,22 @@ void tap_send_single(const struct ctx *c, const void *data, size_t l2len) struct iovec iov[2]; size_t iovcnt = 0; - if (c->mode == MODE_PASST) { + switch (c->mode) { + case MODE_PASST: iov[iovcnt] = IOV_OF_LVALUE(vnet_len); iovcnt++; - } - - iov[iovcnt].iov_base = (void *)data; - iov[iovcnt].iov_len = l2len; - iovcnt++; + /* fall through */ + case MODE_PASTA: + iov[iovcnt].iov_base = (void *)data; + iov[iovcnt].iov_len = l2len; + iovcnt++; - tap_send_frames(c, iov, iovcnt, 1); + tap_send_frames(c, iov, iovcnt, 1); + break; + case MODE_VU: + vu_send(c->vdev, data, l2len);I'm a bit uneasy re-introducing a parallel send function for the slow path, rather than using a common tap_send_frames() interface. Any chance you can unify those sensibly? Bearing in mind that this_is_ the slow path, so if you have to copy a bunch of stuff, that's ok.