From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262304; cv=none; d=zohomail.com; s=zohoarc; b=SdCY0w3JsF1nOrr05gzP86f02wgs28/ydlp9btYQSlvCM5oVjbJp75+rvCRDE0LaurV/WOJvR/55Ttw2WdvWK3i4TQaZeqBAqF6mEEpznd5ydnA7mJQR6g7Y3pJJ6zE5IyKvH460GNv+mBdL7tvBr61iwz3jm9ijO/p/ykyEel8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262304; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=pip8H5LhecWwBCKCriggPkC9ndhlmXdBoFMDWaLqcpM=; b=eyyc3yQ5Yx2K+jSvfXaxipa4vPUaMSdEiXXHKBaNCVqMsneJrISExqLYbnT9UlSizQnuwTjgdWzeBp5j2FXDfm6TR0Lt2ALJisrXSE8wUJpZmLjNqePu7gZ3yCavijQi9+KCSid1FQF1K52uLUP6d3qjXx7Mxhhd11jkPFGGoCQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1750262304314918.5531634304793; Wed, 18 Jun 2025 08:58:24 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvAW-0003Ee-Pt; Wed, 18 Jun 2025 11:57:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAQ-0003Cp-J5 for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:40 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAN-00088e-No for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:38 -0400 Received: from mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-665-3M_W288pOFuNCU32EsZtYQ-1; Wed, 18 Jun 2025 11:57:30 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 275D3195608A; Wed, 18 Jun 2025 15:57:29 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B8E1C18003FC; Wed, 18 Jun 2025 15:57:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262254; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pip8H5LhecWwBCKCriggPkC9ndhlmXdBoFMDWaLqcpM=; b=RtfaTJDg9T6fQ/St6xXmchdfXMyiT6QALPxJmUmkB2ygEYTbyraGcWbXH+nzZPyrvwf/b0 jQaM7W5oiq13al67kfMTOI5bUkLJCjCB/qNEQu/DUW/MrJi3rLxhNyA3BVvku9kGM2Kudo SsBhIMNywI4JTuNoAbjbmgqpB2G6TKE= X-MC-Unique: 3M_W288pOFuNCU32EsZtYQ-1 X-Mimecast-MFC-AGG-ID: 3M_W288pOFuNCU32EsZtYQ_1750262249 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 01/10] net: Refactor stream logic for reuse in '-net passt' Date: Wed, 18 Jun 2025 17:57:09 +0200 Message-ID: <20250618155718.550968-2-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262305393116600 Content-Type: text/plain; charset="utf-8" To prepare for the implementation of '-net passt', this patch moves the generic stream handling functions from net/stream.c into new net/stream_data.c and net/stream_data.h files. This refactoring introduces a NetStreamData struct that encapsulates the generic fields and logic previously in NetStreamState. The NetStreamState now embeds NetStreamData and delegates the core stream operations to the new generic functions. To maintain flexibility for different users of this generic code, callbacks for send and listen operations are now passed via function pointers within the NetStreamData struct. This allows callers to provide their own specific implementations while reusing the common connection and data transfer logic. Signed-off-by: Laurent Vivier --- net/meson.build | 3 +- net/stream.c | 282 +++++++++++----------------------------------- net/stream_data.c | 193 +++++++++++++++++++++++++++++++ net/stream_data.h | 31 +++++ 4 files changed, 290 insertions(+), 219 deletions(-) create mode 100644 net/stream_data.c create mode 100644 net/stream_data.h diff --git a/net/meson.build b/net/meson.build index bb97b4dcbeb6..bb3c011e5a30 100644 --- a/net/meson.build +++ b/net/meson.build @@ -1,6 +1,7 @@ system_ss.add(files( 'announce.c', 'checksum.c', + 'dgram.c', 'dump.c', 'eth.c', 'filter-buffer.c', @@ -12,7 +13,7 @@ system_ss.add(files( 'queue.c', 'socket.c', 'stream.c', - 'dgram.c', + 'stream_data.c', 'util.c', )) =20 diff --git a/net/stream.c b/net/stream.c index 6152d2a05e52..d893f02cabe3 100644 --- a/net/stream.c +++ b/net/stream.c @@ -27,173 +27,50 @@ =20 #include "net/net.h" #include "clients.h" -#include "monitor/monitor.h" #include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/option.h" -#include "qemu/sockets.h" -#include "qemu/iov.h" -#include "qemu/main-loop.h" -#include "qemu/cutils.h" -#include "io/channel.h" -#include "io/channel-socket.h" #include "io/net-listener.h" #include "qapi/qapi-events-net.h" #include "qapi/qapi-visit-sockets.h" #include "qapi/clone-visitor.h" =20 +#include "stream_data.h" + typedef struct NetStreamState { - NetClientState nc; - QIOChannel *listen_ioc; - QIONetListener *listener; - QIOChannel *ioc; - guint ioc_read_tag; - guint ioc_write_tag; - SocketReadState rs; - unsigned int send_index; /* number of bytes sent*/ + NetStreamData data; uint32_t reconnect_ms; guint timer_tag; SocketAddress *addr; } NetStreamState; =20 -static void net_stream_listen(QIONetListener *listener, - QIOChannelSocket *cioc, - void *opaque); static void net_stream_arm_reconnect(NetStreamState *s); =20 -static gboolean net_stream_writable(QIOChannel *ioc, - GIOCondition condition, - gpointer data) -{ - NetStreamState *s =3D data; - - s->ioc_write_tag =3D 0; - - qemu_flush_queued_packets(&s->nc); - - return G_SOURCE_REMOVE; -} - static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - NetStreamState *s =3D DO_UPCAST(NetStreamState, nc, nc); - uint32_t len =3D htonl(size); - struct iovec iov[] =3D { - { - .iov_base =3D &len, - .iov_len =3D sizeof(len), - }, { - .iov_base =3D (void *)buf, - .iov_len =3D size, - }, - }; - struct iovec local_iov[2]; - unsigned int nlocal_iov; - size_t remaining; - ssize_t ret; - - remaining =3D iov_size(iov, 2) - s->send_index; - nlocal_iov =3D iov_copy(local_iov, 2, iov, 2, s->send_index, remaining= ); - ret =3D qio_channel_writev(s->ioc, local_iov, nlocal_iov, NULL); - if (ret =3D=3D QIO_CHANNEL_ERR_BLOCK) { - ret =3D 0; /* handled further down */ - } - if (ret =3D=3D -1) { - s->send_index =3D 0; - return -errno; - } - if (ret < (ssize_t)remaining) { - s->send_index +=3D ret; - s->ioc_write_tag =3D qio_channel_add_watch(s->ioc, G_IO_OUT, - net_stream_writable, s, N= ULL); - return 0; - } - s->send_index =3D 0; - return size; -} - -static gboolean net_stream_send(QIOChannel *ioc, - GIOCondition condition, - gpointer data); - -static void net_stream_send_completed(NetClientState *nc, ssize_t len) -{ - NetStreamState *s =3D DO_UPCAST(NetStreamState, nc, nc); - - if (!s->ioc_read_tag) { - s->ioc_read_tag =3D qio_channel_add_watch(s->ioc, G_IO_IN, - net_stream_send, s, NULL); - } -} + NetStreamData *d =3D DO_UPCAST(NetStreamData, nc, nc); =20 -static void net_stream_rs_finalize(SocketReadState *rs) -{ - NetStreamState *s =3D container_of(rs, NetStreamState, rs); - - if (qemu_send_packet_async(&s->nc, rs->buf, - rs->packet_len, - net_stream_send_completed) =3D=3D 0) { - if (s->ioc_read_tag) { - g_source_remove(s->ioc_read_tag); - s->ioc_read_tag =3D 0; - } - } + return net_stream_data_receive(d, buf, size); } =20 static gboolean net_stream_send(QIOChannel *ioc, GIOCondition condition, gpointer data) { - NetStreamState *s =3D data; - int size; - int ret; - QEMU_UNINITIALIZED char buf1[NET_BUFSIZE]; - const char *buf; - - size =3D qio_channel_read(s->ioc, buf1, sizeof(buf1), NULL); - if (size < 0) { - if (errno !=3D EWOULDBLOCK) { - goto eoc; - } - } else if (size =3D=3D 0) { - /* end of connection */ - eoc: - s->ioc_read_tag =3D 0; - if (s->ioc_write_tag) { - g_source_remove(s->ioc_write_tag); - s->ioc_write_tag =3D 0; - } - if (s->listener) { - qemu_set_info_str(&s->nc, "listening"); - qio_net_listener_set_client_func(s->listener, net_stream_liste= n, - s, NULL); - } - object_unref(OBJECT(s->ioc)); - s->ioc =3D NULL; - - net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); - s->nc.link_down =3D true; + if (net_stream_data_send(ioc, condition, data) =3D=3D G_SOURCE_REMOVE)= { + NetStreamState *s =3D DO_UPCAST(NetStreamState, data, data); =20 - qapi_event_send_netdev_stream_disconnected(s->nc.name); + qapi_event_send_netdev_stream_disconnected(s->data.nc.name); net_stream_arm_reconnect(s); =20 return G_SOURCE_REMOVE; } - buf =3D buf1; - - ret =3D net_fill_rstate(&s->rs, (const uint8_t *)buf, size); - - if (ret =3D=3D -1) { - goto eoc; - } =20 return G_SOURCE_CONTINUE; } =20 static void net_stream_cleanup(NetClientState *nc) { - NetStreamState *s =3D DO_UPCAST(NetStreamState, nc, nc); + NetStreamState *s =3D DO_UPCAST(NetStreamState, data.nc, nc); if (s->timer_tag) { g_source_remove(s->timer_tag); s->timer_tag =3D 0; @@ -202,28 +79,28 @@ static void net_stream_cleanup(NetClientState *nc) qapi_free_SocketAddress(s->addr); s->addr =3D NULL; } - if (s->ioc) { - if (QIO_CHANNEL_SOCKET(s->ioc)->fd !=3D -1) { - if (s->ioc_read_tag) { - g_source_remove(s->ioc_read_tag); - s->ioc_read_tag =3D 0; + if (s->data.ioc) { + if (QIO_CHANNEL_SOCKET(s->data.ioc)->fd !=3D -1) { + if (s->data.ioc_read_tag) { + g_source_remove(s->data.ioc_read_tag); + s->data.ioc_read_tag =3D 0; } - if (s->ioc_write_tag) { - g_source_remove(s->ioc_write_tag); - s->ioc_write_tag =3D 0; + if (s->data.ioc_write_tag) { + g_source_remove(s->data.ioc_write_tag); + s->data.ioc_write_tag =3D 0; } } - object_unref(OBJECT(s->ioc)); - s->ioc =3D NULL; + object_unref(OBJECT(s->data.ioc)); + s->data.ioc =3D NULL; } - if (s->listen_ioc) { - if (s->listener) { - qio_net_listener_disconnect(s->listener); - object_unref(OBJECT(s->listener)); - s->listener =3D NULL; + if (s->data.listen_ioc) { + if (s->data.listener) { + qio_net_listener_disconnect(s->data.listener); + object_unref(OBJECT(s->data.listener)); + s->data.listener =3D NULL; } - object_unref(OBJECT(s->listen_ioc)); - s->listen_ioc =3D NULL; + object_unref(OBJECT(s->data.listen_ioc)); + s->data.listen_ioc =3D NULL; } } =20 @@ -235,23 +112,13 @@ static NetClientInfo net_stream_info =3D { }; =20 static void net_stream_listen(QIONetListener *listener, - QIOChannelSocket *cioc, - void *opaque) + QIOChannelSocket *cioc, gpointer data) { - NetStreamState *s =3D opaque; + NetStreamData *d =3D data; SocketAddress *addr; char *uri; =20 - object_ref(OBJECT(cioc)); - - qio_net_listener_set_client_func(s->listener, NULL, s, NULL); - - s->ioc =3D QIO_CHANNEL(cioc); - qio_channel_set_name(s->ioc, "stream-server"); - s->nc.link_down =3D false; - - s->ioc_read_tag =3D qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_= send, - s, NULL); + net_stream_data_listen(listener, cioc, data); =20 if (cioc->localAddr.ss_family =3D=3D AF_UNIX) { addr =3D qio_channel_socket_get_local_address(cioc, NULL); @@ -260,22 +127,22 @@ static void net_stream_listen(QIONetListener *listene= r, } g_assert(addr !=3D NULL); uri =3D socket_uri(addr); - qemu_set_info_str(&s->nc, "%s", uri); + qemu_set_info_str(&d->nc, "%s", uri); g_free(uri); - qapi_event_send_netdev_stream_connected(s->nc.name, addr); + qapi_event_send_netdev_stream_connected(d->nc.name, addr); qapi_free_SocketAddress(addr); } =20 static void net_stream_server_listening(QIOTask *task, gpointer opaque) { - NetStreamState *s =3D opaque; - QIOChannelSocket *listen_sioc =3D QIO_CHANNEL_SOCKET(s->listen_ioc); + NetStreamData *d =3D opaque; + QIOChannelSocket *listen_sioc =3D QIO_CHANNEL_SOCKET(d->listen_ioc); SocketAddress *addr; int ret; Error *err =3D NULL; =20 if (qio_task_propagate_error(task, &err)) { - qemu_set_info_str(&s->nc, "error: %s", error_get_pretty(err)); + qemu_set_info_str(&d->nc, "error: %s", error_get_pretty(err)); error_free(err); return; } @@ -284,20 +151,21 @@ static void net_stream_server_listening(QIOTask *task= , gpointer opaque) g_assert(addr !=3D NULL); ret =3D qemu_socket_try_set_nonblock(listen_sioc->fd); if (addr->type =3D=3D SOCKET_ADDRESS_TYPE_FD && ret < 0) { - qemu_set_info_str(&s->nc, "can't use file descriptor %s (errno %d)= ", + qemu_set_info_str(&d->nc, "can't use file descriptor %s (errno %d)= ", addr->u.fd.str, -ret); return; } g_assert(ret =3D=3D 0); qapi_free_SocketAddress(addr); =20 - s->nc.link_down =3D true; - s->listener =3D qio_net_listener_new(); + d->nc.link_down =3D true; + d->listener =3D qio_net_listener_new(); =20 - qemu_set_info_str(&s->nc, "listening"); - net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); - qio_net_listener_set_client_func(s->listener, net_stream_listen, s, NU= LL); - qio_net_listener_add(s->listener, listen_sioc); + qemu_set_info_str(&d->nc, "listening"); + net_socket_rs_init(&d->rs, net_stream_data_rs_finalize, false); + qio_net_listener_set_client_func(d->listener, d->listen, d, + NULL); + qio_net_listener_add(d->listener, listen_sioc); } =20 static int net_stream_server_init(NetClientState *peer, @@ -307,16 +175,18 @@ static int net_stream_server_init(NetClientState *pee= r, Error **errp) { NetClientState *nc; - NetStreamState *s; + NetStreamData *d; QIOChannelSocket *listen_sioc =3D qio_channel_socket_new(); =20 nc =3D qemu_new_net_client(&net_stream_info, peer, model, name); - s =3D DO_UPCAST(NetStreamState, nc, nc); - qemu_set_info_str(&s->nc, "initializing"); + d =3D DO_UPCAST(NetStreamData, nc, nc); + d->send =3D net_stream_send; + d->listen =3D net_stream_listen; + qemu_set_info_str(&d->nc, "initializing"); =20 - s->listen_ioc =3D QIO_CHANNEL(listen_sioc); + d->listen_ioc =3D QIO_CHANNEL(listen_sioc); qio_channel_socket_listen_async(listen_sioc, addr, 0, - net_stream_server_listening, s, + net_stream_server_listening, d, NULL, NULL); =20 return 0; @@ -325,49 +195,23 @@ static int net_stream_server_init(NetClientState *pee= r, static void net_stream_client_connected(QIOTask *task, gpointer opaque) { NetStreamState *s =3D opaque; - QIOChannelSocket *sioc =3D QIO_CHANNEL_SOCKET(s->ioc); + NetStreamData *d =3D &s->data; + QIOChannelSocket *sioc =3D QIO_CHANNEL_SOCKET(d->ioc); SocketAddress *addr; gchar *uri; - int ret; - Error *err =3D NULL; =20 - if (qio_task_propagate_error(task, &err)) { - qemu_set_info_str(&s->nc, "error: %s", error_get_pretty(err)); - error_free(err); - goto error; + if (net_stream_data_client_connected(task, d) =3D=3D -1) { + net_stream_arm_reconnect(s); + return; } =20 addr =3D qio_channel_socket_get_remote_address(sioc, NULL); g_assert(addr !=3D NULL); uri =3D socket_uri(addr); - qemu_set_info_str(&s->nc, "%s", uri); + qemu_set_info_str(&d->nc, "%s", uri); g_free(uri); - - ret =3D qemu_socket_try_set_nonblock(sioc->fd); - if (addr->type =3D=3D SOCKET_ADDRESS_TYPE_FD && ret < 0) { - qemu_set_info_str(&s->nc, "can't use file descriptor %s (errno %d)= ", - addr->u.fd.str, -ret); - qapi_free_SocketAddress(addr); - goto error; - } - g_assert(ret =3D=3D 0); - - net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); - - /* Disable Nagle algorithm on TCP sockets to reduce latency */ - qio_channel_set_delay(s->ioc, false); - - s->ioc_read_tag =3D qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_= send, - s, NULL); - s->nc.link_down =3D false; - qapi_event_send_netdev_stream_connected(s->nc.name, addr); + qapi_event_send_netdev_stream_connected(d->nc.name, addr); qapi_free_SocketAddress(addr); - - return; -error: - object_unref(OBJECT(s->ioc)); - s->ioc =3D NULL; - net_stream_arm_reconnect(s); } =20 static gboolean net_stream_reconnect(gpointer data) @@ -378,7 +222,7 @@ static gboolean net_stream_reconnect(gpointer data) s->timer_tag =3D 0; =20 sioc =3D qio_channel_socket_new(); - s->ioc =3D QIO_CHANNEL(sioc); + s->data.ioc =3D QIO_CHANNEL(sioc); qio_channel_socket_connect_async(sioc, s->addr, net_stream_client_connected, s, NULL, NULL); @@ -388,7 +232,7 @@ static gboolean net_stream_reconnect(gpointer data) static void net_stream_arm_reconnect(NetStreamState *s) { if (s->reconnect_ms && s->timer_tag =3D=3D 0) { - qemu_set_info_str(&s->nc, "connecting"); + qemu_set_info_str(&s->data.nc, "connecting"); s->timer_tag =3D g_timeout_add(s->reconnect_ms, net_stream_reconne= ct, s); } } @@ -405,11 +249,13 @@ static int net_stream_client_init(NetClientState *pee= r, QIOChannelSocket *sioc =3D qio_channel_socket_new(); =20 nc =3D qemu_new_net_client(&net_stream_info, peer, model, name); - s =3D DO_UPCAST(NetStreamState, nc, nc); - qemu_set_info_str(&s->nc, "connecting"); + s =3D DO_UPCAST(NetStreamState, data.nc, nc); + qemu_set_info_str(&s->data.nc, "connecting"); =20 - s->ioc =3D QIO_CHANNEL(sioc); - s->nc.link_down =3D true; + s->data.ioc =3D QIO_CHANNEL(sioc); + s->data.nc.link_down =3D true; + s->data.send =3D net_stream_send; + s->data.listen =3D net_stream_listen; =20 s->reconnect_ms =3D reconnect_ms; if (reconnect_ms) { diff --git a/net/stream_data.c b/net/stream_data.c new file mode 100644 index 000000000000..5af27e0d1d6a --- /dev/null +++ b/net/stream_data.c @@ -0,0 +1,193 @@ +/* + * net stream generic functions + * + * Copyright Red Hat + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/iov.h" +#include "qapi/error.h" +#include "net/net.h" +#include "io/channel.h" +#include "io/net-listener.h" + +#include "stream_data.h" + +static gboolean net_stream_data_writable(QIOChannel *ioc, + GIOCondition condition, gpointer = data) +{ + NetStreamData *d =3D data; + + d->ioc_write_tag =3D 0; + + qemu_flush_queued_packets(&d->nc); + + return G_SOURCE_REMOVE; +} + +ssize_t net_stream_data_receive(NetStreamData *d, const uint8_t *buf, + size_t size) +{ + uint32_t len =3D htonl(size); + struct iovec iov[] =3D { + { + .iov_base =3D &len, + .iov_len =3D sizeof(len), + }, { + .iov_base =3D (void *)buf, + .iov_len =3D size, + }, + }; + struct iovec local_iov[2]; + unsigned int nlocal_iov; + size_t remaining; + ssize_t ret; + + remaining =3D iov_size(iov, 2) - d->send_index; + nlocal_iov =3D iov_copy(local_iov, 2, iov, 2, d->send_index, remaining= ); + ret =3D qio_channel_writev(d->ioc, local_iov, nlocal_iov, NULL); + if (ret =3D=3D QIO_CHANNEL_ERR_BLOCK) { + ret =3D 0; /* handled further down */ + } + if (ret =3D=3D -1) { + d->send_index =3D 0; + return -errno; + } + if (ret < (ssize_t)remaining) { + d->send_index +=3D ret; + d->ioc_write_tag =3D qio_channel_add_watch(d->ioc, G_IO_OUT, + net_stream_data_writable,= d, + NULL); + return 0; + } + d->send_index =3D 0; + return size; +} + +static void net_stream_data_send_completed(NetClientState *nc, ssize_t len) +{ + NetStreamData *d =3D DO_UPCAST(NetStreamData, nc, nc); + + if (!d->ioc_read_tag) { + d->ioc_read_tag =3D qio_channel_add_watch(d->ioc, G_IO_IN, d->send= , d, + NULL); + } +} + +void net_stream_data_rs_finalize(SocketReadState *rs) +{ + NetStreamData *d =3D container_of(rs, NetStreamData, rs); + + if (qemu_send_packet_async(&d->nc, rs->buf, + rs->packet_len, + net_stream_data_send_completed) =3D=3D 0) { + if (d->ioc_read_tag) { + g_source_remove(d->ioc_read_tag); + d->ioc_read_tag =3D 0; + } + } +} + +gboolean net_stream_data_send(QIOChannel *ioc, GIOCondition condition, + NetStreamData *d) +{ + int size; + int ret; + QEMU_UNINITIALIZED char buf1[NET_BUFSIZE]; + const char *buf; + + size =3D qio_channel_read(d->ioc, buf1, sizeof(buf1), NULL); + if (size < 0) { + if (errno !=3D EWOULDBLOCK) { + goto eoc; + } + } else if (size =3D=3D 0) { + /* end of connection */ + eoc: + d->ioc_read_tag =3D 0; + if (d->ioc_write_tag) { + g_source_remove(d->ioc_write_tag); + d->ioc_write_tag =3D 0; + } + if (d->listener) { + qemu_set_info_str(&d->nc, "listening"); + qio_net_listener_set_client_func(d->listener, + d->listen, d, NULL); + } + object_unref(OBJECT(d->ioc)); + d->ioc =3D NULL; + + net_socket_rs_init(&d->rs, net_stream_data_rs_finalize, false); + d->nc.link_down =3D true; + + return G_SOURCE_REMOVE; + } + buf =3D buf1; + + ret =3D net_fill_rstate(&d->rs, (const uint8_t *)buf, size); + + if (ret =3D=3D -1) { + goto eoc; + } + + return G_SOURCE_CONTINUE; +} + +void net_stream_data_listen(QIONetListener *listener, + QIOChannelSocket *cioc, + NetStreamData *d) +{ + object_ref(OBJECT(cioc)); + + qio_net_listener_set_client_func(d->listener, NULL, d, NULL); + + d->ioc =3D QIO_CHANNEL(cioc); + qio_channel_set_name(d->ioc, "stream-server"); + d->nc.link_down =3D false; + + d->ioc_read_tag =3D qio_channel_add_watch(d->ioc, G_IO_IN, d->send, d,= NULL); +} + +int net_stream_data_client_connected(QIOTask *task, NetStreamData *d) +{ + QIOChannelSocket *sioc =3D QIO_CHANNEL_SOCKET(d->ioc); + SocketAddress *addr; + int ret; + Error *err =3D NULL; + + if (qio_task_propagate_error(task, &err)) { + qemu_set_info_str(&d->nc, "error: %s", error_get_pretty(err)); + error_free(err); + goto error; + } + + addr =3D qio_channel_socket_get_remote_address(sioc, NULL); + g_assert(addr !=3D NULL); + + ret =3D qemu_socket_try_set_nonblock(sioc->fd); + if (addr->type =3D=3D SOCKET_ADDRESS_TYPE_FD && ret < 0) { + qemu_set_info_str(&d->nc, "can't use file descriptor %s (errno %d)= ", + addr->u.fd.str, -ret); + qapi_free_SocketAddress(addr); + goto error; + } + g_assert(ret =3D=3D 0); + qapi_free_SocketAddress(addr); + + net_socket_rs_init(&d->rs, net_stream_data_rs_finalize, false); + + /* Disable Nagle algorithm on TCP sockets to reduce latency */ + qio_channel_set_delay(d->ioc, false); + + d->ioc_read_tag =3D qio_channel_add_watch(d->ioc, G_IO_IN, d->send, d,= NULL); + d->nc.link_down =3D false; + + return 0; +error: + object_unref(OBJECT(d->ioc)); + d->ioc =3D NULL; + + return -1; +} diff --git a/net/stream_data.h b/net/stream_data.h new file mode 100644 index 000000000000..b868625665ae --- /dev/null +++ b/net/stream_data.h @@ -0,0 +1,31 @@ +/* + * net stream generic functions + * + * Copyright Red Hat + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +typedef struct NetStreamData { + NetClientState nc; + QIOChannel *ioc; + guint ioc_read_tag; + guint ioc_write_tag; + SocketReadState rs; + unsigned int send_index; /* number of bytes sent*/ + QIOChannelFunc send; + /* server data */ + QIOChannel *listen_ioc; + QIONetListener *listener; + QIONetListenerClientFunc listen; +} NetStreamData; + +ssize_t net_stream_data_receive(NetStreamData *d, const uint8_t *buf, + size_t size); +void net_stream_data_rs_finalize(SocketReadState *rs); +gboolean net_stream_data_send(QIOChannel *ioc, GIOCondition condition, + NetStreamData *d); +int net_stream_data_client_connected(QIOTask *task, NetStreamData *d); +void net_stream_data_listen(QIONetListener *listener, + QIOChannelSocket *cioc, + NetStreamData *d); --=20 2.49.0 From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262462; cv=none; d=zohomail.com; s=zohoarc; b=V261s51tXwWER20xVmFjMpfYHOdD1waRvs5pKMxTDVoQAa0SRkBwD0CpTI51nH0SAR0RVO/LirdzA24Kd9jaGdN5akRTl+wfP0Me+KSGgTtY6cLLzJUgWEAn7RuBCpkr+hxfEKI8ii8VbFL2XV1yk6XtM7QYfEM+L/nfWMDMcUs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262462; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=XMSAIGjZQm7v/llfYTxAtUXEfhFeRyEzAV9SpCA0wyQ=; b=L1KgvVlIKzvRmfHxORC23RdIKjqEPxornQpDsIIn9tRIcYVKWUNfb8jCHWQFnNmgTVROPcF6qWg3kcqx74a0sXARj5Yhw8pgtVfyyRUPDdgzaAph+Au0T16WbklGmdiYx1RchAylYKqn4wlMPiNfN+mvex8RrKt6vgYgurrY/n0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1750262460860287.4553509820073; Wed, 18 Jun 2025 09:01:00 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvAZ-0003FO-Ld; Wed, 18 Jun 2025 11:57:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAR-0003Cu-Ks for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:40 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAP-00088o-UQ for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:39 -0400 Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-369-2u4Qr764NPqg_NzhgdvtOg-1; Wed, 18 Jun 2025 11:57:34 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7308F19560B5; Wed, 18 Jun 2025 15:57:33 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 991C9180045B; Wed, 18 Jun 2025 15:57:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262256; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XMSAIGjZQm7v/llfYTxAtUXEfhFeRyEzAV9SpCA0wyQ=; b=V+lwvK4G56pVi9XxnKeIpsaSpzozzBh2lPeY5FfaedZRMKwmIO33ROJ+cCQ5vWfzwIJtIW kunm77IOP9eXWTtbfaEoyhPHgYQxoSEiLQTOci13qhmWx2Mkd5JiceJDpnH52ruIc+3Wsu 93fr9F0HxpJVySWwBEaAIZ+mFfNCR2o= X-MC-Unique: 2u4Qr764NPqg_NzhgdvtOg-1 X-Mimecast-MFC-AGG-ID: 2u4Qr764NPqg_NzhgdvtOg_1750262253 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 02/10] net: Define net_client_set_link() Date: Wed, 18 Jun 2025 17:57:10 +0200 Message-ID: <20250618155718.550968-3-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262465589116600 Content-Type: text/plain; charset="utf-8" The code to set the link status is currently located in qmp_set_link(). This function identifies the device by name, searches for the corresponding NetClientState, and then updates the link status. In some parts of the code, such as vhost-user.c, the NetClientState are already available. Calling qmp_set_link() from these locations leads to a redundant search for the clients. This patch refactors the logic by introducing a new function, net_client_set_link(), which accepts a NetClientState array directly. qmp_set_link() is simplified to be a wrapper that performs the client search and then calls the new function. The vhost-user implementation is updated to use net_client_set_link() directly, thereby eliminating the unnecessary client lookup. Signed-off-by: Laurent Vivier --- include/net/net.h | 1 + net/net.c | 32 ++++++++++++++++++++------------ net/vhost-user.c | 4 ++-- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/include/net/net.h b/include/net/net.h index cdd5b109b0d2..ac59b593ba48 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -298,6 +298,7 @@ void net_client_parse(QemuOptsList *opts_list, const ch= ar *optstr); void show_netdevs(void); void net_init_clients(void); void net_check_clients(void); +void net_client_set_link(NetClientState **ncs, int queues, bool up); void net_cleanup(void); void hmp_host_net_add(Monitor *mon, const QDict *qdict); void hmp_host_net_remove(Monitor *mon, const QDict *qdict); diff --git a/net/net.c b/net/net.c index 39d6f28158a3..cfa2d8e95827 100644 --- a/net/net.c +++ b/net/net.c @@ -1601,21 +1601,11 @@ void colo_notify_filters_event(int event, Error **e= rrp) } } =20 -void qmp_set_link(const char *name, bool up, Error **errp) +void net_client_set_link(NetClientState **ncs, int queues, bool up) { - NetClientState *ncs[MAX_QUEUE_NUM]; NetClientState *nc; - int queues, i; - - queues =3D qemu_find_net_clients_except(name, ncs, - NET_CLIENT_DRIVER__MAX, - MAX_QUEUE_NUM); + int i; =20 - if (queues =3D=3D 0) { - error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, - "Device '%s' not found", name); - return; - } nc =3D ncs[0]; =20 for (i =3D 0; i < queues; i++) { @@ -1646,6 +1636,24 @@ void qmp_set_link(const char *name, bool up, Error *= *errp) } } =20 +void qmp_set_link(const char *name, bool up, Error **errp) +{ + NetClientState *ncs[MAX_QUEUE_NUM]; + int queues; + + queues =3D qemu_find_net_clients_except(name, ncs, + NET_CLIENT_DRIVER__MAX, + MAX_QUEUE_NUM); + + if (queues =3D=3D 0) { + error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, + "Device '%s' not found", name); + return; + } + + net_client_set_link(ncs, queues, up); +} + static void net_vm_change_state_handler(void *opaque, bool running, RunState state) { diff --git a/net/vhost-user.c b/net/vhost-user.c index 0b235e50c650..10ac8dc0b3d7 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -264,7 +264,7 @@ static void chr_closed_bh(void *opaque) vhost_user_save_acked_features(ncs[i]); } =20 - qmp_set_link(name, false, &err); + net_client_set_link(ncs, queues, false); =20 qemu_chr_fe_set_handlers(&s->chr, NULL, NULL, net_vhost_user_event, NULL, opaque, NULL, true); @@ -300,7 +300,7 @@ static void net_vhost_user_event(void *opaque, QEMUChrE= vent event) } s->watch =3D qemu_chr_fe_add_watch(&s->chr, G_IO_HUP, net_vhost_user_watch, s); - qmp_set_link(name, true, &err); + net_client_set_link(ncs, queues, true); s->started =3D true; qapi_event_send_netdev_vhost_user_connected(name, chr->label); break; --=20 2.49.0 From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262322; cv=none; d=zohomail.com; s=zohoarc; b=VdaXWTHnJbcMbvFe45Gyiyr61fTaHZ1YLbQd4S2mHaZ1joOGli+srv72I0IpE6OPzes4JswBnDcLLoZAucaJNxWNRSbQkjtjDsP9N2+9X5W0RoHjVdzMTkJPmNeaRUzqzqryg8zhjcWmxABnN4mLVzfs0yKQW3SzWhSgdpeOdhE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262322; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=VT/epj+hWtrtTUYjkPFrWfPk206BN+ojqPS0GojuHPA=; b=UrP6OT7dVLybUa4yXBtR4rBM628V4zybDxwUPTcQJNZOeb3uQ6My3PVPp2HDf7ZsUl0dEGRwqQBnxrcUjJEoV/mkXgTs4rDb47ZV5xV9KzTI0XQKbxGDc8Mxz4Pgzmj/EUGbfPE+KuSYm/q3+XupXyZduQtTIdykbYVJURMtCLA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1750262322115678.4036940177367; Wed, 18 Jun 2025 08:58:42 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvAb-0003Fk-GJ; Wed, 18 Jun 2025 11:57:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAX-0003F5-Ts for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:46 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAV-00089h-4M for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:45 -0400 Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-176-5Hjs37pcPOmeMabTHRDdfA-1; Wed, 18 Jun 2025 11:57:39 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0B66B1956096; Wed, 18 Jun 2025 15:57:38 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E307218003FC; Wed, 18 Jun 2025 15:57:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262262; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VT/epj+hWtrtTUYjkPFrWfPk206BN+ojqPS0GojuHPA=; b=K33GB92FlTSGUcHC8/G2Z00WNIDSQUWd6DbjU58Bf46tWIGDP/OE5+/nntx6d+3U+dv4kM wrtxXLEYrXSOE7TwoTqO1zZX6kUZ33vzDomWFCmZ6bDjBwH+VRyAjVcC1O/hn5CbAmDXsR KTILoeeFRSMFvLEpM1bPa7GRCNZZUKA= X-MC-Unique: 5Hjs37pcPOmeMabTHRDdfA-1 X-Mimecast-MFC-AGG-ID: 5Hjs37pcPOmeMabTHRDdfA_1750262258 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 03/10] net: Introduce helper to identify vhost-user clients Date: Wed, 18 Jun 2025 17:57:11 +0200 Message-ID: <20250618155718.550968-4-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262323247116600 Content-Type: text/plain; charset="utf-8" Currently, several parts of the codebase check if a network client is a vhost-user backend by directly comparing its type against the NET_CLIENT_DRIVER_VHOST_USER enum. This creates a tight coupling between virtio/vhost-net drivers and the internal implementation details of the vhost-user net client. To improve abstraction and reduce this coupling, this patch introduces a new helper function, qemu_is_vhost_user(). This function allows callers to query if a client is of the vhost-user type without needing to know about the specific enum value. The mechanism uses a new is_vhost_user function pointer in the NetClientInfo structure, which is implemented by the vhost-user backend. All existing direct checks are replaced with calls to the new helper. This simplifies the logic in vhost_net.c and virtio-net.c, making the code cleaner and more maintainable. Signed-off-by: Laurent Vivier --- hw/net/vhost_net.c | 33 +++++++++++++++------------------ hw/net/virtio-net.c | 18 ++++++++++-------- include/net/net.h | 3 +++ net/net.c | 9 +++++++++ net/vhost-user.c | 8 ++++++++ 5 files changed, 45 insertions(+), 26 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 891f235a0a6e..41d21e687ed9 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -98,27 +98,24 @@ static const int user_feature_bits[] =3D { =20 static const int *vhost_net_get_feature_bits(struct vhost_net *net) { - const int *feature_bits =3D 0; + if (net->nc->info->type =3D=3D NET_CLIENT_DRIVER_TAP) { + return kernel_feature_bits; + } + + if (qemu_is_vhost_user(net->nc)) { + return user_feature_bits; + } =20 - switch (net->nc->info->type) { - case NET_CLIENT_DRIVER_TAP: - feature_bits =3D kernel_feature_bits; - break; - case NET_CLIENT_DRIVER_VHOST_USER: - feature_bits =3D user_feature_bits; - break; #ifdef CONFIG_VHOST_NET_VDPA - case NET_CLIENT_DRIVER_VHOST_VDPA: - feature_bits =3D vdpa_feature_bits; - break; -#endif - default: - error_report("Feature bits not defined for this type: %d", - net->nc->info->type); - break; + if (net->nc->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_VDPA) { + return vdpa_feature_bits; } +#endif =20 - return feature_bits; + error_report("Feature bits not defined for this type: %d", + net->nc->info->type); + + return 0; } =20 uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) @@ -525,7 +522,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *= ncs, * because vhost user doesn't interrupt masking/unmasking * properly. */ - if (net->nc->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_USER) { + if (qemu_is_vhost_user(net->nc)) { dev->use_guest_notifier_mask =3D false; } } diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index eb93607b8c76..1367d2b581b1 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -679,13 +679,15 @@ static int virtio_net_max_tx_queue_size(VirtIONet *n) return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; } =20 - switch(peer->info->type) { - case NET_CLIENT_DRIVER_VHOST_USER: - case NET_CLIENT_DRIVER_VHOST_VDPA: + if (qemu_is_vhost_user(peer)) { return VIRTQUEUE_MAX_SIZE; - default: - return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; - }; + } + + if (peer->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_VDPA) { + return VIRTQUEUE_MAX_SIZE; + } + + return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; } =20 static int peer_attach(VirtIONet *n, int index) @@ -696,7 +698,7 @@ static int peer_attach(VirtIONet *n, int index) return 0; } =20 - if (nc->peer->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_USER) { + if (qemu_is_vhost_user(nc->peer)) { vhost_set_vring_enable(nc->peer, 1); } =20 @@ -719,7 +721,7 @@ static int peer_detach(VirtIONet *n, int index) return 0; } =20 - if (nc->peer->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_USER) { + if (qemu_is_vhost_user(nc->peer)) { vhost_set_vring_enable(nc->peer, 0); } =20 diff --git a/include/net/net.h b/include/net/net.h index ac59b593ba48..2c3b22f564b6 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -67,6 +67,7 @@ typedef void (SocketReadStateFinalize)(SocketReadState *r= s); typedef void (NetAnnounce)(NetClientState *); typedef bool (SetSteeringEBPF)(NetClientState *, int); typedef bool (NetCheckPeerType)(NetClientState *, ObjectClass *, Error **); +typedef bool (IsVHostUser)(NetClientState *); =20 typedef struct NetClientInfo { NetClientDriver type; @@ -92,6 +93,7 @@ typedef struct NetClientInfo { NetAnnounce *announce; SetSteeringEBPF *set_steering_ebpf; NetCheckPeerType *check_peer_type; + IsVHostUser *is_vhost_user; } NetClientInfo; =20 struct NetClientState { @@ -191,6 +193,7 @@ int qemu_get_vnet_hdr_len(NetClientState *nc); void qemu_set_vnet_hdr_len(NetClientState *nc, int len); int qemu_set_vnet_le(NetClientState *nc, bool is_le); int qemu_set_vnet_be(NetClientState *nc, bool is_be); +bool qemu_is_vhost_user(NetClientState *nc); void qemu_macaddr_default_if_unset(MACAddr *macaddr); /** * qemu_find_nic_info: Obtain NIC configuration information diff --git a/net/net.c b/net/net.c index cfa2d8e95827..8726c59915a3 100644 --- a/net/net.c +++ b/net/net.c @@ -586,6 +586,15 @@ int qemu_set_vnet_le(NetClientState *nc, bool is_le) #endif } =20 +bool qemu_is_vhost_user(NetClientState *nc) +{ + if (nc->info->is_vhost_user) { + return nc->info->is_vhost_user(nc); + } + + return false; +} + int qemu_set_vnet_be(NetClientState *nc, bool is_be) { #if HOST_BIG_ENDIAN diff --git a/net/vhost-user.c b/net/vhost-user.c index 10ac8dc0b3d7..4b4d02c56740 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -221,6 +221,13 @@ static bool vhost_user_check_peer_type(NetClientState = *nc, ObjectClass *oc, return true; } =20 +static bool vhost_user_is_vhost_user(NetClientState *nc) +{ + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_USER); + + return true; +} + static NetClientInfo net_vhost_user_info =3D { .type =3D NET_CLIENT_DRIVER_VHOST_USER, .size =3D sizeof(NetVhostUserState), @@ -231,6 +238,7 @@ static NetClientInfo net_vhost_user_info =3D { .set_vnet_be =3D vhost_user_set_vnet_endianness, .set_vnet_le =3D vhost_user_set_vnet_endianness, .check_peer_type =3D vhost_user_check_peer_type, + .is_vhost_user =3D vhost_user_is_vhost_user, }; =20 static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond, --=20 2.49.0 From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262304; cv=none; d=zohomail.com; s=zohoarc; b=gKBDxzDcsJI1borK/BbI+t7ujEFQPLmdj9vR4VpiMe1bteLi5T/wuesWF7raolbK3KlevxgbCdI7D1uw7P3sSI/9QZqB0z2sxljNN37ryODD/5KKdUYbTzrBk6EAGh4p+HeCWg0GnjuCuyRpnyoyPFEpWkVh6gimy1bvUOx1LYQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262303; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Jb0CgELTRKz19zoBNNtzjKkT3GlOqs/ymBmwcRa0rdA=; b=CJoTJfqey7ul8B7WMWcwT72Q7BPCHDwxF9WCwQxoH65XgzlbNCGCxfiIv8otiq2qQQFwneNic1OUn109IyzNdhYGmnvNRjk2D8bVuXX5S0C3VXrT+wYzSVdHN+OwAcd9srKj62Bg2PodO3xZeNw35MqiGpHL4S+nv+wBVu4It7o= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1750262303992691.1964521914432; Wed, 18 Jun 2025 08:58:23 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvAc-0003G7-Ax; Wed, 18 Jun 2025 11:57:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAZ-0003FT-UL for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:48 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAY-00089v-0o for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:47 -0400 Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-397-rUevBL8EONm10nal903QHg-1; Wed, 18 Jun 2025 11:57:43 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B0E4D180028C; Wed, 18 Jun 2025 15:57:42 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id B3C7C180045B; Wed, 18 Jun 2025 15:57:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262265; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Jb0CgELTRKz19zoBNNtzjKkT3GlOqs/ymBmwcRa0rdA=; b=ZSdZFgH7x1lntf9G725l9GR1m8JYE7M0DHq43eDPh8xL5JX4ZchEhkRQJfuAhhrHDbW0rm FDjp1VdVqkofp04sgWoyGL2Drjsu/0YoKAVc6EopbTRV2epBRlQ7frgkZ2g5mm7Nr0lm35 cqr3Kd6RE3frwJVbRAKo4vB7M1g11jg= X-MC-Unique: rUevBL8EONm10nal903QHg-1 X-Mimecast-MFC-AGG-ID: rUevBL8EONm10nal903QHg_1750262262 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 04/10] net: Add get_vhost_net callback to NetClientInfo Date: Wed, 18 Jun 2025 17:57:12 +0200 Message-ID: <20250618155718.550968-5-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262305344116600 Content-Type: text/plain; charset="utf-8" The get_vhost_net() function previously contained a large switch statement to find the VHostNetState pointer based on the net client's type. This created a tight coupling, requiring the generic vhost layer to be aware of every specific backend that supported vhost, such as tap, vhost-user, and vhost-vdpa. This approach is not scalable and requires modifying a central function for any new backend. It also forced each backend to expose its internal getter function in a public header file. This patch refactors the logic by introducing a new get_vhost_net function pointer to the NetClientInfo struct. The central get_vhost_net() function is now a simple, generic dispatcher that invokes the callback provided by the net client. Each backend now implements its own private getter and registers it in its NetClientInfo. Signed-off-by: Laurent Vivier --- hw/net/vhost_net.c | 31 ++++--------------------------- include/net/net.h | 2 ++ include/net/tap.h | 3 --- include/net/vhost-user.h | 1 - include/net/vhost-vdpa.h | 2 -- net/tap-win32.c | 5 ----- net/tap.c | 20 +++++++++++++------- net/vhost-user.c | 3 ++- net/vhost-vdpa.c | 4 +++- 9 files changed, 24 insertions(+), 47 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 41d21e687ed9..16dadd022e75 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -646,41 +646,18 @@ void vhost_net_config_mask(VHostNetState *net, VirtIO= Device *dev, bool mask) { vhost_config_mask(&net->dev, dev, mask); } + VHostNetState *get_vhost_net(NetClientState *nc) { - VHostNetState *vhost_net =3D 0; - if (!nc) { return 0; } =20 - switch (nc->info->type) { - case NET_CLIENT_DRIVER_TAP: - vhost_net =3D tap_get_vhost_net(nc); - /* - * tap_get_vhost_net() can return NULL if a tap net-device backend= is - * created with 'vhost=3Doff' option, 'vhostforce=3Doff' or no vho= st or - * vhostforce or vhostfd options at all. Please see net_init_tap_o= ne(). - * Hence, we omit the assertion here. - */ - break; -#ifdef CONFIG_VHOST_NET_USER - case NET_CLIENT_DRIVER_VHOST_USER: - vhost_net =3D vhost_user_get_vhost_net(nc); - assert(vhost_net); - break; -#endif -#ifdef CONFIG_VHOST_NET_VDPA - case NET_CLIENT_DRIVER_VHOST_VDPA: - vhost_net =3D vhost_vdpa_get_vhost_net(nc); - assert(vhost_net); - break; -#endif - default: - break; + if (nc->info->get_vhost_net) { + return nc->info->get_vhost_net(nc); } =20 - return vhost_net; + return NULL; } =20 int vhost_set_vring_enable(NetClientState *nc, int enable) diff --git a/include/net/net.h b/include/net/net.h index 2c3b22f564b6..8a62cd6e8aab 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -68,6 +68,7 @@ typedef void (NetAnnounce)(NetClientState *); typedef bool (SetSteeringEBPF)(NetClientState *, int); typedef bool (NetCheckPeerType)(NetClientState *, ObjectClass *, Error **); typedef bool (IsVHostUser)(NetClientState *); +typedef struct vhost_net *(GetVHostNet)(NetClientState *nc); =20 typedef struct NetClientInfo { NetClientDriver type; @@ -94,6 +95,7 @@ typedef struct NetClientInfo { SetSteeringEBPF *set_steering_ebpf; NetCheckPeerType *check_peer_type; IsVHostUser *is_vhost_user; + GetVHostNet *get_vhost_net; } NetClientInfo; =20 struct NetClientState { diff --git a/include/net/tap.h b/include/net/tap.h index 5d585515f9e3..6f34f13eae44 100644 --- a/include/net/tap.h +++ b/include/net/tap.h @@ -33,7 +33,4 @@ int tap_disable(NetClientState *nc); =20 int tap_get_fd(NetClientState *nc); =20 -struct vhost_net; -struct vhost_net *tap_get_vhost_net(NetClientState *nc); - #endif /* QEMU_NET_TAP_H */ diff --git a/include/net/vhost-user.h b/include/net/vhost-user.h index 35bf61970985..0b233a267345 100644 --- a/include/net/vhost-user.h +++ b/include/net/vhost-user.h @@ -12,7 +12,6 @@ #define VHOST_USER_H =20 struct vhost_net; -struct vhost_net *vhost_user_get_vhost_net(NetClientState *nc); uint64_t vhost_user_get_acked_features(NetClientState *nc); void vhost_user_save_acked_features(NetClientState *nc); =20 diff --git a/include/net/vhost-vdpa.h b/include/net/vhost-vdpa.h index b81f9a6f2a0e..916ead3793d9 100644 --- a/include/net/vhost-vdpa.h +++ b/include/net/vhost-vdpa.h @@ -14,8 +14,6 @@ =20 #define TYPE_VHOST_VDPA "vhost-vdpa" =20 -struct vhost_net *vhost_vdpa_get_vhost_net(NetClientState *nc); - extern const int vdpa_feature_bits[]; =20 #endif /* VHOST_VDPA_H */ diff --git a/net/tap-win32.c b/net/tap-win32.c index 671dee970f7a..38baf90e0b3f 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -704,11 +704,6 @@ static void tap_win32_send(void *opaque) } } =20 -struct vhost_net *tap_get_vhost_net(NetClientState *nc) -{ - return NULL; -} - static NetClientInfo net_tap_win32_info =3D { .type =3D NET_CLIENT_DRIVER_TAP, .size =3D sizeof(TAPState), diff --git a/net/tap.c b/net/tap.c index ae1c7e398321..4beba6d7a784 100644 --- a/net/tap.c +++ b/net/tap.c @@ -329,6 +329,18 @@ int tap_get_fd(NetClientState *nc) return s->fd; } =20 +/* + * tap_get_vhost_net() can return NULL if a tap net-device backend is + * created with 'vhost=3Doff' option, 'vhostforce=3Doff' or no vhost or + * vhostforce or vhostfd options at all. Please see net_init_tap_one(). + */ +static VHostNetState *tap_get_vhost_net(NetClientState *nc) +{ + TAPState *s =3D DO_UPCAST(TAPState, nc, nc); + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_TAP); + return s->vhost_net; +} + /* fd support */ =20 static NetClientInfo net_tap_info =3D { @@ -347,6 +359,7 @@ static NetClientInfo net_tap_info =3D { .set_vnet_le =3D tap_set_vnet_le, .set_vnet_be =3D tap_set_vnet_be, .set_steering_ebpf =3D tap_set_steering_ebpf, + .get_vhost_net =3D tap_get_vhost_net, }; =20 static TAPState *net_tap_fd_init(NetClientState *peer, @@ -980,13 +993,6 @@ free_fail: return 0; } =20 -VHostNetState *tap_get_vhost_net(NetClientState *nc) -{ - TAPState *s =3D DO_UPCAST(TAPState, nc, nc); - assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_TAP); - return s->vhost_net; -} - int tap_enable(NetClientState *nc) { TAPState *s =3D DO_UPCAST(TAPState, nc, nc); diff --git a/net/vhost-user.c b/net/vhost-user.c index 4b4d02c56740..2caa7e56f7a0 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -32,7 +32,7 @@ typedef struct NetVhostUserState { bool started; } NetVhostUserState; =20 -VHostNetState *vhost_user_get_vhost_net(NetClientState *nc) +static struct vhost_net *vhost_user_get_vhost_net(NetClientState *nc) { NetVhostUserState *s =3D DO_UPCAST(NetVhostUserState, nc, nc); assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_USER); @@ -239,6 +239,7 @@ static NetClientInfo net_vhost_user_info =3D { .set_vnet_le =3D vhost_user_set_vnet_endianness, .check_peer_type =3D vhost_user_check_peer_type, .is_vhost_user =3D vhost_user_is_vhost_user, + .get_vhost_net =3D vhost_user_get_vhost_net, }; =20 static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond, diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 58d738945dbc..0b86c917ed68 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -132,7 +132,7 @@ static const uint64_t vdpa_svq_device_features =3D =20 #define VHOST_VDPA_NET_CVQ_ASID 1 =20 -VHostNetState *vhost_vdpa_get_vhost_net(NetClientState *nc) +static struct vhost_net *vhost_vdpa_get_vhost_net(NetClientState *nc) { VhostVDPAState *s =3D DO_UPCAST(VhostVDPAState, nc, nc); assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_VDPA); @@ -432,6 +432,7 @@ static NetClientInfo net_vhost_vdpa_info =3D { .set_vnet_le =3D vhost_vdpa_set_vnet_le, .check_peer_type =3D vhost_vdpa_check_peer_type, .set_steering_ebpf =3D vhost_vdpa_set_steering_ebpf, + .get_vhost_net =3D vhost_vdpa_get_vhost_net, }; =20 static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index, @@ -1287,6 +1288,7 @@ static NetClientInfo net_vhost_vdpa_cvq_info =3D { .has_ufo =3D vhost_vdpa_has_ufo, .check_peer_type =3D vhost_vdpa_check_peer_type, .set_steering_ebpf =3D vhost_vdpa_set_steering_ebpf, + .get_vhost_net =3D vhost_vdpa_get_vhost_net, }; =20 /* --=20 2.49.0 From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262340; cv=none; d=zohomail.com; s=zohoarc; b=i5s4qiY4awVvmn/FbbVuvpH73+wDWV/EOLTm9tA4mmu1/wkKHEtEO4PIdc3nkKZK9EwaInpzOiY6/NSghyZUpO3quL0OvDxFsJoMphPuVutAl3Co5FvlOemcBLAtRXH2a63DiWPrHyCge6zkpo2z7CaMguNCMxMcNge6CfhGogU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262340; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=i5HqPeqt2g0OivT9RMZt8olKZ8J7MkH3B51wrkUa+lE=; b=P/b3zrMM/CMt+ErPhDYeAJHUAjYvoS/klIXBatHEivCBS3NwpHwRu0ELgxMrObB13MnFkjyIjsMPGfyibc8KKBJc54hyl2qQnsNFlplX/BeDyEviatjEiCXzZPUh25x80qYFFO3Ghh6DbQDD1h7+8d4Z0mpG6uctoIswoXDYkro= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 175026234036112.925273307791372; Wed, 18 Jun 2025 08:59:00 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvAg-0003HD-H1; Wed, 18 Jun 2025 11:57:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAe-0003Gz-AI for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:52 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAc-0008AG-C1 for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:52 -0400 Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-248-9utjXzv2OCicZIqd0_hc1Q-1; Wed, 18 Jun 2025 11:57:48 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1AB2B1809C85; Wed, 18 Jun 2025 15:57:47 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3799A18002B0; Wed, 18 Jun 2025 15:57:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262269; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=i5HqPeqt2g0OivT9RMZt8olKZ8J7MkH3B51wrkUa+lE=; b=d4HJsO0kRyCieb87wuN8cTA8BCMYvDFs6ACLyeq0LOoIDNUQV3B6nln7+I1ppNSVORA/Is FMaBjnVYwUM/ETtQZfe71brGCpjUG1mshKNsnyBHJkcIcR+ZFs4P5pcrrlX8UGp9ublhLO VDh3CgEnciibKiOpcgEoj2nTiWz+8mg= X-MC-Unique: 9utjXzv2OCicZIqd0_hc1Q-1 X-Mimecast-MFC-AGG-ID: 9utjXzv2OCicZIqd0_hc1Q_1750262267 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 05/10] net: Consolidate vhost feature bits into NetClientInfo Date: Wed, 18 Jun 2025 17:57:13 +0200 Message-ID: <20250618155718.550968-6-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262341795116600 Content-Type: text/plain; charset="utf-8" Previously, the vhost_net_get_feature_bits() function in hw/net/vhost_net.c used a large switch statement to determine the appropriate feature bits based on the NetClientDriver type. This created unnecessary coupling between the generic vhost layer and specific network backends (like TAP, vhost-user, and vhost-vdpa). This patch moves the definition of vhost feature bits directly into the NetClientInfo structure for each relevant network client. This refactoring centralizes feature bit definitions where they're needed, making code easier to add new vhost-enabled network backends in the future without modifying core vhost logic. Signed-off-by: Laurent Vivier --- hw/net/vhost_net.c | 80 ++-------------------------------------- include/net/net.h | 1 + include/net/vhost-vdpa.h | 2 - net/tap.c | 19 ++++++++++ net/vhost-user.c | 43 +++++++++++++++++++++ net/vhost-vdpa.c | 4 +- 6 files changed, 70 insertions(+), 79 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 16dadd022e75..3dff819d2dbd 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -36,86 +36,14 @@ #include "hw/virtio/virtio-bus.h" #include "linux-headers/linux/vhost.h" =20 - -/* Features supported by host kernel. */ -static const int kernel_feature_bits[] =3D { - VIRTIO_F_NOTIFY_ON_EMPTY, - VIRTIO_RING_F_INDIRECT_DESC, - VIRTIO_RING_F_EVENT_IDX, - VIRTIO_NET_F_MRG_RXBUF, - VIRTIO_F_VERSION_1, - VIRTIO_NET_F_MTU, - VIRTIO_F_IOMMU_PLATFORM, - VIRTIO_F_RING_PACKED, - VIRTIO_F_RING_RESET, - VIRTIO_F_IN_ORDER, - VIRTIO_F_NOTIFICATION_DATA, - VIRTIO_NET_F_RSC_EXT, - VIRTIO_NET_F_HASH_REPORT, - VHOST_INVALID_FEATURE_BIT -}; - -/* Features supported by others. */ -static const int user_feature_bits[] =3D { - VIRTIO_F_NOTIFY_ON_EMPTY, - VIRTIO_F_NOTIFICATION_DATA, - VIRTIO_RING_F_INDIRECT_DESC, - VIRTIO_RING_F_EVENT_IDX, - - VIRTIO_F_ANY_LAYOUT, - VIRTIO_F_VERSION_1, - VIRTIO_NET_F_CSUM, - VIRTIO_NET_F_GUEST_CSUM, - VIRTIO_NET_F_GSO, - VIRTIO_NET_F_GUEST_TSO4, - VIRTIO_NET_F_GUEST_TSO6, - VIRTIO_NET_F_GUEST_ECN, - VIRTIO_NET_F_GUEST_UFO, - VIRTIO_NET_F_HOST_TSO4, - VIRTIO_NET_F_HOST_TSO6, - VIRTIO_NET_F_HOST_ECN, - VIRTIO_NET_F_HOST_UFO, - VIRTIO_NET_F_MRG_RXBUF, - VIRTIO_NET_F_MTU, - VIRTIO_F_IOMMU_PLATFORM, - VIRTIO_F_RING_PACKED, - VIRTIO_F_RING_RESET, - VIRTIO_F_IN_ORDER, - VIRTIO_NET_F_RSS, - VIRTIO_NET_F_RSC_EXT, - VIRTIO_NET_F_HASH_REPORT, - VIRTIO_NET_F_GUEST_USO4, - VIRTIO_NET_F_GUEST_USO6, - VIRTIO_NET_F_HOST_USO, - - /* This bit implies RARP isn't sent by QEMU out of band */ - VIRTIO_NET_F_GUEST_ANNOUNCE, - - VIRTIO_NET_F_MQ, - - VHOST_INVALID_FEATURE_BIT -}; - static const int *vhost_net_get_feature_bits(struct vhost_net *net) { - if (net->nc->info->type =3D=3D NET_CLIENT_DRIVER_TAP) { - return kernel_feature_bits; - } - - if (qemu_is_vhost_user(net->nc)) { - return user_feature_bits; + if (net->nc->info->vhost_feature_bits =3D=3D NULL) { + error_report("Feature bits not defined for this type: %d", + net->nc->info->type); } =20 -#ifdef CONFIG_VHOST_NET_VDPA - if (net->nc->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_VDPA) { - return vdpa_feature_bits; - } -#endif - - error_report("Feature bits not defined for this type: %d", - net->nc->info->type); - - return 0; + return net->nc->info->vhost_feature_bits; } =20 uint64_t vhost_net_get_features(struct vhost_net *net, uint64_t features) diff --git a/include/net/net.h b/include/net/net.h index 8a62cd6e8aab..dd11be11a39f 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -94,6 +94,7 @@ typedef struct NetClientInfo { NetAnnounce *announce; SetSteeringEBPF *set_steering_ebpf; NetCheckPeerType *check_peer_type; + const int *vhost_feature_bits; IsVHostUser *is_vhost_user; GetVHostNet *get_vhost_net; } NetClientInfo; diff --git a/include/net/vhost-vdpa.h b/include/net/vhost-vdpa.h index 916ead3793d9..f8d7d6c9045b 100644 --- a/include/net/vhost-vdpa.h +++ b/include/net/vhost-vdpa.h @@ -14,6 +14,4 @@ =20 #define TYPE_VHOST_VDPA "vhost-vdpa" =20 -extern const int vdpa_feature_bits[]; - #endif /* VHOST_VDPA_H */ diff --git a/net/tap.c b/net/tap.c index 4beba6d7a784..9e5b1a02d8d3 100644 --- a/net/tap.c +++ b/net/tap.c @@ -42,11 +42,29 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/sockets.h" +#include "hw/virtio/vhost.h" =20 #include "net/tap.h" =20 #include "net/vhost_net.h" =20 +static const int kernel_feature_bits[] =3D { + VIRTIO_F_NOTIFY_ON_EMPTY, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + VIRTIO_NET_F_MRG_RXBUF, + VIRTIO_F_VERSION_1, + VIRTIO_NET_F_MTU, + VIRTIO_F_IOMMU_PLATFORM, + VIRTIO_F_RING_PACKED, + VIRTIO_F_RING_RESET, + VIRTIO_F_IN_ORDER, + VIRTIO_F_NOTIFICATION_DATA, + VIRTIO_NET_F_RSC_EXT, + VIRTIO_NET_F_HASH_REPORT, + VHOST_INVALID_FEATURE_BIT +}; + typedef struct TAPState { NetClientState nc; int fd; @@ -360,6 +378,7 @@ static NetClientInfo net_tap_info =3D { .set_vnet_be =3D tap_set_vnet_be, .set_steering_ebpf =3D tap_set_steering_ebpf, .get_vhost_net =3D tap_get_vhost_net, + .vhost_feature_bits =3D kernel_feature_bits, }; =20 static TAPState *net_tap_fd_init(NetClientState *peer, diff --git a/net/vhost-user.c b/net/vhost-user.c index 2caa7e56f7a0..d8fef801de5a 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -12,7 +12,9 @@ #include "clients.h" #include "net/vhost_net.h" #include "net/vhost-user.h" +#include "hw/virtio/vhost.h" #include "hw/virtio/vhost-user.h" +#include "standard-headers/linux/virtio_net.h" #include "chardev/char-fe.h" #include "qapi/error.h" #include "qapi/qapi-commands-net.h" @@ -22,6 +24,46 @@ #include "qemu/option.h" #include "trace.h" =20 +static const int user_feature_bits[] =3D { + VIRTIO_F_NOTIFY_ON_EMPTY, + VIRTIO_F_NOTIFICATION_DATA, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + + VIRTIO_F_ANY_LAYOUT, + VIRTIO_F_VERSION_1, + VIRTIO_NET_F_CSUM, + VIRTIO_NET_F_GUEST_CSUM, + VIRTIO_NET_F_GSO, + VIRTIO_NET_F_GUEST_TSO4, + VIRTIO_NET_F_GUEST_TSO6, + VIRTIO_NET_F_GUEST_ECN, + VIRTIO_NET_F_GUEST_UFO, + VIRTIO_NET_F_HOST_TSO4, + VIRTIO_NET_F_HOST_TSO6, + VIRTIO_NET_F_HOST_ECN, + VIRTIO_NET_F_HOST_UFO, + VIRTIO_NET_F_MRG_RXBUF, + VIRTIO_NET_F_MTU, + VIRTIO_F_IOMMU_PLATFORM, + VIRTIO_F_RING_PACKED, + VIRTIO_F_RING_RESET, + VIRTIO_F_IN_ORDER, + VIRTIO_NET_F_RSS, + VIRTIO_NET_F_RSC_EXT, + VIRTIO_NET_F_HASH_REPORT, + VIRTIO_NET_F_GUEST_USO4, + VIRTIO_NET_F_GUEST_USO6, + VIRTIO_NET_F_HOST_USO, + + /* This bit implies RARP isn't sent by QEMU out of band */ + VIRTIO_NET_F_GUEST_ANNOUNCE, + + VIRTIO_NET_F_MQ, + + VHOST_INVALID_FEATURE_BIT +}; + typedef struct NetVhostUserState { NetClientState nc; CharBackend chr; /* only queue index 0 */ @@ -240,6 +282,7 @@ static NetClientInfo net_vhost_user_info =3D { .check_peer_type =3D vhost_user_check_peer_type, .is_vhost_user =3D vhost_user_is_vhost_user, .get_vhost_net =3D vhost_user_get_vhost_net, + .vhost_feature_bits =3D user_feature_bits, }; =20 static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond, diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 0b86c917ed68..bd699066a3ab 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -55,7 +55,7 @@ typedef struct VhostVDPAState { * with the exception of VHOST_INVALID_FEATURE_BIT, * which should always be the last entry. */ -const int vdpa_feature_bits[] =3D { +static const int vdpa_feature_bits[] =3D { VIRTIO_F_ANY_LAYOUT, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_NOTIFY_ON_EMPTY, @@ -433,6 +433,7 @@ static NetClientInfo net_vhost_vdpa_info =3D { .check_peer_type =3D vhost_vdpa_check_peer_type, .set_steering_ebpf =3D vhost_vdpa_set_steering_ebpf, .get_vhost_net =3D vhost_vdpa_get_vhost_net, + .vhost_feature_bits =3D vdpa_feature_bits, }; =20 static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index, @@ -1289,6 +1290,7 @@ static NetClientInfo net_vhost_vdpa_cvq_info =3D { .check_peer_type =3D vhost_vdpa_check_peer_type, .set_steering_ebpf =3D vhost_vdpa_set_steering_ebpf, .get_vhost_net =3D vhost_vdpa_get_vhost_net, + .vhost_feature_bits =3D vdpa_feature_bits, }; =20 /* --=20 2.49.0 From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262480; cv=none; d=zohomail.com; s=zohoarc; b=NAPJaqYVkyJmxDOT7lubIKKnFLvVD6x+lmfikEtnACSAGsF710vZitTBXumtEB/eUz1UViDKYEKmZ+4ygz9J/faGi9bRPDwn3HcrHk0yL2sGkftj9E+QYG/VFQxobH6D7QhrEOF+fcq2egUmLTvHYqjg7h/6Q5xu7MftxzjLYqc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262480; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=qaib6U2aKJ5dc9kwGx+BE5kvhAn3cL9g74aPPQnsqqk=; b=M23CkB1kW9bjrKhXRRBsPnupqUdJ68uDL9qNWntx6gwwfzUzjUq8IfDfW0W15U0meZNlrI/n8TX90mxcehd+dy8EXjNyONdaZm1hp7bUxFz7BvlZOn0hS7HFgQQv+xI0IC6YWQt1XVPj7HL0zk5s5PZMWc/OOradlr/LOlldzIA= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1750262480449390.7135642844679; Wed, 18 Jun 2025 09:01:20 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvAn-0003IM-5Z; Wed, 18 Jun 2025 11:58:01 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAk-0003Hk-8h for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:58 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAi-0008B0-9Q for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:57:57 -0400 Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-639-zoj3SqwENUq8srl_8c9tMQ-1; Wed, 18 Jun 2025 11:57:52 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3240E180028D; Wed, 18 Jun 2025 15:57:51 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 890BE18003FC; Wed, 18 Jun 2025 15:57:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262275; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qaib6U2aKJ5dc9kwGx+BE5kvhAn3cL9g74aPPQnsqqk=; b=ZzvbJ7EhFNRvWbd3SL4jIksl5nE+IXnkQca745WgFWxh6Z0fwF3sn8vNH3TyRMQX/MSpcF zRwMkuUy2zojfCEXadLOppezGURgSTrDfEQm4iuyl9/oOMKe+0uIwZRAiAkAHMItRyVXiP yJn6Ja0OFH4Bn6/2G+60QFkqVYdWW4U= X-MC-Unique: zoj3SqwENUq8srl_8c9tMQ-1 X-Mimecast-MFC-AGG-ID: zoj3SqwENUq8srl_8c9tMQ_1750262271 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 06/10] net: Add get_acked_features callback to NetClientInfo Date: Wed, 18 Jun 2025 17:57:14 +0200 Message-ID: <20250618155718.550968-7-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262482296116600 Content-Type: text/plain; charset="utf-8" This patch continues the effort to decouple the generic vhost layer from specific network backend implementations. Previously, the vhost_net initialization code contained a hardcoded check for the vhost-user client type to retrieve its acked features by calling vhost_user_get_acked_features(). This exposed an internal vhost-user function in a public header and coupled the two modules. Following the pattern of recent commits, this patch introduces a generic helper, qemu_get_acked_features(), and a corresponding get_acked_features callback in the NetClientInfo struct. The vhost-user backend is updated to provide this callback, and its getter function is now static. The call site in vhost_net.c is simplified to use the new generic helper, removing the type check and the direct dependency. Signed-off-by: Laurent Vivier --- hw/net/vhost_net.c | 18 +++++++----------- include/net/net.h | 4 ++++ include/net/vhost-user.h | 2 -- net/net.c | 10 ++++++++++ net/vhost-user.c | 3 ++- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 3dff819d2dbd..9cfe41b40b41 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -245,8 +245,8 @@ struct vhost_net *vhost_net_init(VhostNetOptions *optio= ns) int r; bool backend_kernel =3D options->backend_type =3D=3D VHOST_BACKEND_TYP= E_KERNEL; struct vhost_net *net =3D g_new0(struct vhost_net, 1); - uint64_t features =3D 0; Error *local_err =3D NULL; + uint64_t features; =20 if (!options->net_backend) { fprintf(stderr, "vhost-net requires net backend to be setup\n"); @@ -297,17 +297,13 @@ struct vhost_net *vhost_net_init(VhostNetOptions *opt= ions) } =20 /* Set sane init value. Override when guest acks. */ -#ifdef CONFIG_VHOST_NET_USER - if (net->nc->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_USER) { - features =3D vhost_user_get_acked_features(net->nc); - if (~net->dev.features & features) { - fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 - " for backend\n", - (uint64_t)(~net->dev.features & features)); - goto fail; - } + features =3D qemu_get_acked_features(net->nc); + if (~net->dev.features & features) { + fprintf(stderr, "vhost lacks feature mask 0x%" PRIx64 + " for backend\n", + (uint64_t)(~net->dev.features & features)); + goto fail; } -#endif =20 vhost_net_ack_features(net, features); =20 diff --git a/include/net/net.h b/include/net/net.h index dd11be11a39f..37dc97a06752 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -69,6 +69,7 @@ typedef bool (SetSteeringEBPF)(NetClientState *, int); typedef bool (NetCheckPeerType)(NetClientState *, ObjectClass *, Error **); typedef bool (IsVHostUser)(NetClientState *); typedef struct vhost_net *(GetVHostNet)(NetClientState *nc); +typedef uint64_t (GetAckedFeatures)(NetClientState *nc); =20 typedef struct NetClientInfo { NetClientDriver type; @@ -97,6 +98,7 @@ typedef struct NetClientInfo { const int *vhost_feature_bits; IsVHostUser *is_vhost_user; GetVHostNet *get_vhost_net; + GetAckedFeatures *get_acked_features; } NetClientInfo; =20 struct NetClientState { @@ -198,6 +200,8 @@ int qemu_set_vnet_le(NetClientState *nc, bool is_le); int qemu_set_vnet_be(NetClientState *nc, bool is_be); bool qemu_is_vhost_user(NetClientState *nc); void qemu_macaddr_default_if_unset(MACAddr *macaddr); +uint64_t qemu_get_acked_features(NetClientState *nc); + /** * qemu_find_nic_info: Obtain NIC configuration information * @typename: Name of device object type diff --git a/include/net/vhost-user.h b/include/net/vhost-user.h index 0b233a267345..a4d0ce4b8dd1 100644 --- a/include/net/vhost-user.h +++ b/include/net/vhost-user.h @@ -11,8 +11,6 @@ #ifndef VHOST_USER_H #define VHOST_USER_H =20 -struct vhost_net; -uint64_t vhost_user_get_acked_features(NetClientState *nc); void vhost_user_save_acked_features(NetClientState *nc); =20 #endif /* VHOST_USER_H */ diff --git a/net/net.c b/net/net.c index 8726c59915a3..ba051441053f 100644 --- a/net/net.c +++ b/net/net.c @@ -608,6 +608,16 @@ int qemu_set_vnet_be(NetClientState *nc, bool is_be) #endif } =20 +uint64_t qemu_get_acked_features(NetClientState *nc) +{ + if (nc->info->get_acked_features) { + return nc->info->get_acked_features(nc); + } + + return 0; +} + + int qemu_can_receive_packet(NetClientState *nc) { if (nc->receive_disabled) { diff --git a/net/vhost-user.c b/net/vhost-user.c index d8fef801de5a..e590b39503de 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -81,7 +81,7 @@ static struct vhost_net *vhost_user_get_vhost_net(NetClie= ntState *nc) return s->vhost_net; } =20 -uint64_t vhost_user_get_acked_features(NetClientState *nc) +static uint64_t vhost_user_get_acked_features(NetClientState *nc) { NetVhostUserState *s =3D DO_UPCAST(NetVhostUserState, nc, nc); assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_USER); @@ -283,6 +283,7 @@ static NetClientInfo net_vhost_user_info =3D { .is_vhost_user =3D vhost_user_is_vhost_user, .get_vhost_net =3D vhost_user_get_vhost_net, .vhost_feature_bits =3D user_feature_bits, + .get_acked_features =3D vhost_user_get_acked_features, }; =20 static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond, --=20 2.49.0 From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262362; cv=none; d=zohomail.com; s=zohoarc; b=YQ3U/YX6ot3WN8ogwRJRVQLS6S9aSj644NCmaHU8bUMvRfWgsjsuLcrimxnfMBsR4EzARFt0EprcSspYzykIHDUK7EKOngC4cgqD+uLymssIBW8iVy0P8qxnjYPiGX9LuUwOdjT8ZdW7r45JRmbAOis10izoh197B9eX9eSSu1U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262362; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=/AORrHkTo1CSRa5FEHRdhnhWesUlfPSJmqnq3AxSgsQ=; b=EelHIs9NPgH13eowtIm6vq8MgX3zWetcwLEXpG1Yn0Evu6DUwIu4lLbQIIqvIO144CHjPVkn5EXG2Jtv//FUED86fYatm0FKtM6bE/hj8GCJZ6bcRPii/37Rr49KKxvOpWfwnUgJhzpiRLCNpqp+wxRbYGpE/2sjX0Pd8+s604s= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1750262362619535.9985925869167; Wed, 18 Jun 2025 08:59:22 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvAt-0003Ir-Rq; Wed, 18 Jun 2025 11:58:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAr-0003If-3N for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:58:05 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAp-0008BO-B9 for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:58:04 -0400 Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-582-kXfnp2bPNZ-P_qZc7wqOjg-1; Wed, 18 Jun 2025 11:57:56 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4FABF195609F; Wed, 18 Jun 2025 15:57:55 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id A3DE9180045B; Wed, 18 Jun 2025 15:57:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262282; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/AORrHkTo1CSRa5FEHRdhnhWesUlfPSJmqnq3AxSgsQ=; b=dblZntx7NEXOtcNpHEF7GF1hdUqIwMqSbZlEoRbjOozHI6kZrGogSpgNJeypMgnUSbRbs+ /ihJtxuWi/5p73s0C6vuMkKqRj6IN5PF6PdYux2aoZRTGTDhSzKPWjOyRwmdRQqA6tkhlk d0227lbjHCSMMAFHhApboEAmjLkNxvQ= X-MC-Unique: kXfnp2bPNZ-P_qZc7wqOjg-1 X-Mimecast-MFC-AGG-ID: kXfnp2bPNZ-P_qZc7wqOjg_1750262275 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 07/10] net: Add save_acked_features callback to NetClientInfo Date: Wed, 18 Jun 2025 17:57:15 +0200 Message-ID: <20250618155718.550968-8-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.133.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262363718116600 Content-Type: text/plain; charset="utf-8" This patch completes the series of refactorings aimed at decoupling the generic vhost layer from specific network backends. The final remaining dependency was in vhost_net_save_acked_features, which contained a hardcoded check for the vhost-user client type. This commit applies the now-established callback pattern, introducing a save_acked_features function pointer to NetClientInfo and converting the vhost_net function into a generic dispatcher. The vhost-user backend provides the callback, making its function static. With this change, no other module has a direct dependency on the vhost-user implementation. This cleanup allows for the complete removal of the net/vhost-user.h header file. Signed-off-by: Laurent Vivier --- hw/net/vhost_net-stub.c | 1 - hw/net/vhost_net.c | 7 ++----- include/net/net.h | 2 ++ include/net/vhost-user.h | 16 ---------------- net/vhost-user-stub.c | 1 - net/vhost-user.c | 4 ++-- 6 files changed, 6 insertions(+), 25 deletions(-) delete mode 100644 include/net/vhost-user.h diff --git a/hw/net/vhost_net-stub.c b/hw/net/vhost_net-stub.c index 72df6d757e4d..dab9943172da 100644 --- a/hw/net/vhost_net-stub.c +++ b/hw/net/vhost_net-stub.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "net/net.h" #include "net/tap.h" -#include "net/vhost-user.h" =20 #include "hw/virtio/virtio-net.h" #include "net/vhost_net.h" diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c index 9cfe41b40b41..e5890bac8200 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -16,7 +16,6 @@ #include "qemu/osdep.h" #include "net/net.h" #include "net/tap.h" -#include "net/vhost-user.h" #include "net/vhost-vdpa.h" =20 #include "standard-headers/linux/vhost_types.h" @@ -80,11 +79,9 @@ uint64_t vhost_net_get_acked_features(VHostNetState *net) =20 void vhost_net_save_acked_features(NetClientState *nc) { -#ifdef CONFIG_VHOST_NET_USER - if (nc->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_USER) { - vhost_user_save_acked_features(nc); + if (nc->info->save_acked_features) { + nc->info->save_acked_features(nc); } -#endif } =20 static void vhost_net_disable_notifiers_nvhosts(VirtIODevice *dev, diff --git a/include/net/net.h b/include/net/net.h index 37dc97a06752..179ffee5bd11 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -70,6 +70,7 @@ typedef bool (NetCheckPeerType)(NetClientState *, ObjectC= lass *, Error **); typedef bool (IsVHostUser)(NetClientState *); typedef struct vhost_net *(GetVHostNet)(NetClientState *nc); typedef uint64_t (GetAckedFeatures)(NetClientState *nc); +typedef void (SaveAcketFeatures)(NetClientState *nc); =20 typedef struct NetClientInfo { NetClientDriver type; @@ -99,6 +100,7 @@ typedef struct NetClientInfo { IsVHostUser *is_vhost_user; GetVHostNet *get_vhost_net; GetAckedFeatures *get_acked_features; + SaveAcketFeatures *save_acked_features; } NetClientInfo; =20 struct NetClientState { diff --git a/include/net/vhost-user.h b/include/net/vhost-user.h deleted file mode 100644 index a4d0ce4b8dd1..000000000000 --- a/include/net/vhost-user.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * vhost-user.h - * - * Copyright (c) 2013 Virtual Open Systems Sarl. - * - * This work is licensed under the terms of the GNU GPL, version 2 or late= r. - * See the COPYING file in the top-level directory. - * - */ - -#ifndef VHOST_USER_H -#define VHOST_USER_H - -void vhost_user_save_acked_features(NetClientState *nc); - -#endif /* VHOST_USER_H */ diff --git a/net/vhost-user-stub.c b/net/vhost-user-stub.c index 52ab4e13f12a..283dee87db2d 100644 --- a/net/vhost-user-stub.c +++ b/net/vhost-user-stub.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "clients.h" #include "net/vhost_net.h" -#include "net/vhost-user.h" #include "qemu/error-report.h" #include "qapi/error.h" =20 diff --git a/net/vhost-user.c b/net/vhost-user.c index e590b39503de..15609faedb88 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "clients.h" #include "net/vhost_net.h" -#include "net/vhost-user.h" #include "hw/virtio/vhost.h" #include "hw/virtio/vhost-user.h" #include "standard-headers/linux/virtio_net.h" @@ -88,7 +87,7 @@ static uint64_t vhost_user_get_acked_features(NetClientSt= ate *nc) return s->acked_features; } =20 -void vhost_user_save_acked_features(NetClientState *nc) +static void vhost_user_save_acked_features(NetClientState *nc) { NetVhostUserState *s; =20 @@ -284,6 +283,7 @@ static NetClientInfo net_vhost_user_info =3D { .get_vhost_net =3D vhost_user_get_vhost_net, .vhost_feature_bits =3D user_feature_bits, .get_acked_features =3D vhost_user_get_acked_features, + .save_acked_features =3D vhost_user_save_acked_features, }; =20 static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond, --=20 2.49.0 From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262413; cv=none; d=zohomail.com; s=zohoarc; b=LsPJBNNFnFgmhMTb4AaKSGlh9sjYBR8M8znA5XxqtYvUgSUgfLjGDNY2/vl3q1vzZ11DaSUUG7kVNEGC+cbBrNHJN2a6xD+1HOsMkx0ke9IkBufqu3ngAvaEoJJS4Td/I3z4diClGLcBCRDdcvkOq5JoJqzFHf387egMHemWCSA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262413; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=kActzQWZPLXpkEvMFVLwpdhw0QHrTWdRdX5HrsZdUvs=; b=Uzukl+nk8i78CvPGU3MMiuDgUHEpa2dfQc5W10NzK5uN0Lhtf8fWG1qSRItfpSN2Ni5ShMTRVCuslQ0z663OEc23TSzf3VUt/QvvxFO6iMIvmz/tbKZRM/Bq1/AbXmrvv6O3jVryrwQDhFvQu/JMhtKO+vhPFuBY5HKdeKctjuQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 175026241374944.073273419077964; Wed, 18 Jun 2025 09:00:13 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvAu-0003JL-Ud; Wed, 18 Jun 2025 11:58:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAs-0003Is-Fk for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:58:06 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAq-0008Bi-QA for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:58:06 -0400 Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-459-taopULcsNBK1duBOfqX_7w-1; Wed, 18 Jun 2025 11:58:00 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A9AA01800C25; Wed, 18 Jun 2025 15:57:59 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id C095D180045B; Wed, 18 Jun 2025 15:57:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262284; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=kActzQWZPLXpkEvMFVLwpdhw0QHrTWdRdX5HrsZdUvs=; b=UikcorhG9e3oisoMwUfZEeuJAi2HYHbxFVTa6rhtRpyHkW8AWwh16Gq2hQQqI9OtjqRN6g Mx+xM0hEs6s1EbpSGZS7Lg/+ifanPUVOBQ6F22ZhJCAnTayAELAZKvRV1FuoNlT46qTgjm KRERznQWb6+2ZMNxjgiGpVWe6SV0UzY= X-MC-Unique: taopULcsNBK1duBOfqX_7w-1 X-Mimecast-MFC-AGG-ID: taopULcsNBK1duBOfqX_7w_1750262279 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 08/10] net: Allow network backends to advertise max TX queue size Date: Wed, 18 Jun 2025 17:57:16 +0200 Message-ID: <20250618155718.550968-9-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262414300116600 Content-Type: text/plain; charset="utf-8" This commit refactors how the maximum transmit queue size for virtio-net devices is determined, making the mechanism more generic and extensible. Previously, virtio_net_max_tx_queue_size() contained hardcoded checks for specific network backend types (vhost-user and vhost-vdpa) to determine their supported maximum queue size. This created direct dependencies and would require modifications for every new backend that supports variable queue sizes. To improve flexibility, a new max_tx_queue_size field is added to the NetClientInfo structure. This allows each network backend to advertise its supported maximum transmit queue size directly. This change centralizes the configuration of transmit queue sizes, simplifying the virtio-net driver and making it easier to integrate new network backends with diverse queue size capabilities. Signed-off-by: Laurent Vivier --- hw/net/virtio-net.c | 16 ++-------------- include/net/net.h | 1 + net/vhost-user.c | 1 + net/vhost-vdpa.c | 2 ++ 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 1367d2b581b1..2468621375e9 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -671,23 +671,11 @@ static int virtio_net_max_tx_queue_size(VirtIONet *n) { NetClientState *peer =3D n->nic_conf.peers.ncs[0]; =20 - /* - * Backends other than vhost-user or vhost-vdpa don't support max queue - * size. - */ - if (!peer) { + if (!peer || !peer->info->max_tx_queue_size) { return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; } =20 - if (qemu_is_vhost_user(peer)) { - return VIRTQUEUE_MAX_SIZE; - } - - if (peer->info->type =3D=3D NET_CLIENT_DRIVER_VHOST_VDPA) { - return VIRTQUEUE_MAX_SIZE; - } - - return VIRTIO_NET_TX_QUEUE_DEFAULT_SIZE; + return peer->info->max_tx_queue_size; } =20 static int peer_attach(VirtIONet *n, int index) diff --git a/include/net/net.h b/include/net/net.h index 179ffee5bd11..25dd29e07d7f 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -101,6 +101,7 @@ typedef struct NetClientInfo { GetVHostNet *get_vhost_net; GetAckedFeatures *get_acked_features; SaveAcketFeatures *save_acked_features; + int max_tx_queue_size; } NetClientInfo; =20 struct NetClientState { diff --git a/net/vhost-user.c b/net/vhost-user.c index 15609faedb88..89d216714c13 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -284,6 +284,7 @@ static NetClientInfo net_vhost_user_info =3D { .vhost_feature_bits =3D user_feature_bits, .get_acked_features =3D vhost_user_get_acked_features, .save_acked_features =3D vhost_user_save_acked_features, + .max_tx_queue_size =3D VIRTQUEUE_MAX_SIZE, }; =20 static gboolean net_vhost_user_watch(void *do_not_use, GIOCondition cond, diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index bd699066a3ab..4fc5d381ceef 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -434,6 +434,7 @@ static NetClientInfo net_vhost_vdpa_info =3D { .set_steering_ebpf =3D vhost_vdpa_set_steering_ebpf, .get_vhost_net =3D vhost_vdpa_get_vhost_net, .vhost_feature_bits =3D vdpa_feature_bits, + .max_tx_queue_size =3D VIRTQUEUE_MAX_SIZE, }; =20 static int64_t vhost_vdpa_get_vring_group(int device_fd, unsigned vq_index, @@ -1291,6 +1292,7 @@ static NetClientInfo net_vhost_vdpa_cvq_info =3D { .set_steering_ebpf =3D vhost_vdpa_set_steering_ebpf, .get_vhost_net =3D vhost_vdpa_get_vhost_net, .vhost_feature_bits =3D vdpa_feature_bits, + .max_tx_queue_size =3D VIRTQUEUE_MAX_SIZE, }; =20 /* --=20 2.49.0 From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262388; cv=none; d=zohomail.com; s=zohoarc; b=EBeFmflhAYlP9dwzu38RMmxt+PDTt8RP+Dn3vi9KogSTyHh0JBnvqc9rYTJgdOaE9VF7C+yaIOACqBEItLu7+a7emO+ER6cV07xYE0/IERT2XAFJeExQv05FMLEE5vZr+yR0eMBTUM5hL4TFQpYT4EJC/G5YI0ZT3GBSEel+evs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262388; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=gre2I6LOYm1z05m4D6vkpyet4MseB5D8a+Nz9AAXimU=; b=R68U6zL21bEzQGLt7P/pTRbPlmhCfu7PBS7Zvfkdk8WJkgwnoS9FAw/HLU0rJ5Gw6ZpEXg/WOuUUbqddwecGNK0h/m4tL53wXmLtnn7KW0Eh1rD0/JqUBufg0qc/S/WVF1J8i3D8XBulzj5jXHL2lzSWeSL0MazHFrQmuE1YUoU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1750262388227292.5562846549086; Wed, 18 Jun 2025 08:59:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvB2-0003KL-KD; Wed, 18 Jun 2025 11:58:20 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAy-0003Jp-59 for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:58:12 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAv-0008CL-8z for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:58:11 -0400 Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-171-lzwPwYzxMgSFy_cdJYCmSQ-1; Wed, 18 Jun 2025 11:58:05 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 017D41809C85; Wed, 18 Jun 2025 15:58:04 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 281BE18003FC; Wed, 18 Jun 2025 15:57:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262288; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gre2I6LOYm1z05m4D6vkpyet4MseB5D8a+Nz9AAXimU=; b=bI4GtIZNRm+wJlEzHLsc7FoFZaZP7FhxvOUFHHhPnVStMtOw/G6hIDH5sG2tc69/okA9av 1blYUtTb710Gfx8VppGKxw9lI+HH2Cr6y7sxS1XDXsrRYhtjtCaSy+P6hO4c6NmgRBE9EA 5vsnTCvM+7LTrxtr9sQ9qStrOVE7+tc= X-MC-Unique: lzwPwYzxMgSFy_cdJYCmSQ-1 X-Mimecast-MFC-AGG-ID: lzwPwYzxMgSFy_cdJYCmSQ_1750262284 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 09/10] net: Add passt network backend Date: Wed, 18 Jun 2025 17:57:17 +0200 Message-ID: <20250618155718.550968-10-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262390087116600 Content-Type: text/plain; charset="utf-8" This commit introduces support for passt as a new network backend. passt is an unprivileged, user-mode networking solution that provides connectivity for virtual machines by launching an external helper process. The implementation reuses the generic stream data handling logic. It launches the passt binary using GSubprocess, passing it a file descriptor from a socketpair() for communication. QEMU connects to the other end of the socket pair to establish the network data stream. The PID of the passt daemon is tracked via a temporary file to ensure it is terminated when QEMU exits. Signed-off-by: Laurent Vivier --- hmp-commands.hx | 3 + meson.build | 6 + meson_options.txt | 2 + net/clients.h | 4 + net/hub.c | 3 + net/meson.build | 3 + net/net.c | 4 + net/passt.c | 434 ++++++++++++++++++++++++++++++++++++++++++++++ qapi/net.json | 124 +++++++++++++ qemu-options.hx | 18 ++ 10 files changed, 601 insertions(+) create mode 100644 net/passt.c diff --git a/hmp-commands.hx b/hmp-commands.hx index 06746f0afc37..d0e4f35a30af 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1287,6 +1287,9 @@ ERST .name =3D "netdev_add", .args_type =3D "netdev:O", .params =3D "[user|tap|socket|stream|dgram|vde|bridge|hubport|= netmap|vhost-user" +#ifdef CONFIG_PASST + "|passt" +#endif #ifdef CONFIG_AF_XDP "|af-xdp" #endif diff --git a/meson.build b/meson.build index 34729c2a3dd5..485a60a0cb0c 100644 --- a/meson.build +++ b/meson.build @@ -1288,6 +1288,10 @@ if not get_option('slirp').auto() or have_system endif endif =20 +enable_passt =3D get_option('passt') \ + .require(host_os =3D=3D 'linux', error_message: 'passt is supported only= on Linux') \ + .allowed() + vde =3D not_found if not get_option('vde').auto() or have_system or have_tools vde =3D cc.find_library('vdeplug', has_headers: ['libvdeplug.h'], @@ -2541,6 +2545,7 @@ if seccomp.found() config_host_data.set('CONFIG_SECCOMP_SYSRAWRC', seccomp_has_sysrawrc) endif config_host_data.set('CONFIG_PIXMAN', pixman.found()) +config_host_data.set('CONFIG_PASST', enable_passt) config_host_data.set('CONFIG_SLIRP', slirp.found()) config_host_data.set('CONFIG_SNAPPY', snappy.found()) config_host_data.set('CONFIG_SOLARIS', host_os =3D=3D 'sunos') @@ -4965,6 +4970,7 @@ if host_os =3D=3D 'darwin' summary_info +=3D {'vmnet.framework support': vmnet} endif summary_info +=3D {'AF_XDP support': libxdp} +summary_info +=3D {'passt support': enable_passt} summary_info +=3D {'slirp support': slirp} summary_info +=3D {'vde support': vde} summary_info +=3D {'netmap support': have_netmap} diff --git a/meson_options.txt b/meson_options.txt index a442be29958f..3146eec19440 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -234,6 +234,8 @@ option('pixman', type : 'feature', value : 'auto', description: 'pixman support') option('slirp', type: 'feature', value: 'auto', description: 'libslirp user mode network backend support') +option('passt', type: 'feature', value: 'auto', + description: 'passt network backend support') option('vde', type : 'feature', value : 'auto', description: 'vde network backend support') option('vmnet', type : 'feature', value : 'auto', diff --git a/net/clients.h b/net/clients.h index be53794582cf..e786ab420352 100644 --- a/net/clients.h +++ b/net/clients.h @@ -29,6 +29,10 @@ int net_init_dump(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); =20 +#ifdef CONFIG_PASST +int net_init_passt(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); +#endif #ifdef CONFIG_SLIRP int net_init_slirp(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); diff --git a/net/hub.c b/net/hub.c index cba20ebd874f..e3b58b1c4f8e 100644 --- a/net/hub.c +++ b/net/hub.c @@ -285,6 +285,9 @@ void net_hub_check_clients(void) case NET_CLIENT_DRIVER_NIC: has_nic =3D 1; break; +#ifdef CONFIG_PASST + case NET_CLIENT_DRIVER_PASST: +#endif case NET_CLIENT_DRIVER_USER: case NET_CLIENT_DRIVER_TAP: case NET_CLIENT_DRIVER_SOCKET: diff --git a/net/meson.build b/net/meson.build index bb3c011e5a30..da6ea635e95d 100644 --- a/net/meson.build +++ b/net/meson.build @@ -34,6 +34,9 @@ system_ss.add(when: 'CONFIG_TCG', if_true: files('filter-= replay.c')) if have_l2tpv3 system_ss.add(files('l2tpv3.c')) endif +if enable_passt + system_ss.add(files('passt.c')) +endif system_ss.add(when: slirp, if_true: files('slirp.c')) system_ss.add(when: vde, if_true: files('vde.c')) if have_netmap diff --git a/net/net.c b/net/net.c index ba051441053f..e6789378809c 100644 --- a/net/net.c +++ b/net/net.c @@ -1267,6 +1267,9 @@ static int (* const net_client_init_fun[NET_CLIENT_DR= IVER__MAX])( const char *name, NetClientState *peer, Error **errp) =3D { [NET_CLIENT_DRIVER_NIC] =3D net_init_nic, +#ifdef CONFIG_PASST + [NET_CLIENT_DRIVER_PASST] =3D net_init_passt, +#endif #ifdef CONFIG_SLIRP [NET_CLIENT_DRIVER_USER] =3D net_init_slirp, #endif @@ -1372,6 +1375,7 @@ void show_netdevs(void) "dgram", "hubport", "tap", + "passt", #ifdef CONFIG_SLIRP "user", #endif diff --git a/net/passt.c b/net/passt.c new file mode 100644 index 000000000000..ce194b1e02f0 --- /dev/null +++ b/net/passt.c @@ -0,0 +1,434 @@ +/* + * passt network backend + * + * Copyright Red Hat + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "qemu/osdep.h" +#include +#include +#include "net/net.h" +#include "clients.h" +#include "qapi/error.h" +#include "io/net-listener.h" +#include "stream_data.h" + +typedef struct NetPasstState { + NetStreamData data; + GPtrArray *args; + gchar *pidfile; + pid_t pid; +} NetPasstState; + +static int net_passt_stream_start(NetPasstState *s, Error **errp); + +static void net_passt_cleanup(NetClientState *nc) +{ + NetPasstState *s =3D DO_UPCAST(NetPasstState, data.nc, nc); + + kill(s->pid, SIGTERM); + g_remove(s->pidfile); + g_free(s->pidfile); + g_ptr_array_free(s->args, TRUE); +} + +static ssize_t net_passt_receive(NetClientState *nc, const uint8_t *buf, + size_t size) +{ + NetStreamData *d =3D DO_UPCAST(NetStreamData, nc, nc); + + return net_stream_data_receive(d, buf, size); +} + +static gboolean net_passt_send(QIOChannel *ioc, GIOCondition condition, + gpointer data) +{ + if (net_stream_data_send(ioc, condition, data) =3D=3D G_SOURCE_REMOVE)= { + NetPasstState *s =3D DO_UPCAST(NetPasstState, data, data); + Error *error; + + /* we need to restart passt */ + kill(s->pid, SIGTERM); + if (net_passt_stream_start(s, &error) =3D=3D -1) { + error_report_err(error); + } + + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + +static NetClientInfo net_passt_info =3D { + .type =3D NET_CLIENT_DRIVER_PASST, + .size =3D sizeof(NetPasstState), + .receive =3D net_passt_receive, + .cleanup =3D net_passt_cleanup, +}; + +static void net_passt_client_connected(QIOTask *task, gpointer opaque) +{ + NetPasstState *s =3D opaque; + + if (net_stream_data_client_connected(task, &s->data) =3D=3D 0) { + qemu_set_info_str(&s->data.nc, "stream,connected to pid %d", s->pi= d); + } +} + +static int net_passt_start_daemon(NetPasstState *s, int sock, Error **errp) +{ + g_autoptr(GSubprocess) daemon =3D NULL; + g_autofree gchar *contents =3D NULL; + g_autoptr(GError) error =3D NULL; + GSubprocessLauncher *launcher; + + qemu_set_info_str(&s->data.nc, "launching passt"); + + launcher =3D g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_NONE); + g_subprocess_launcher_take_fd(launcher, sock, 3); + + daemon =3D g_subprocess_launcher_spawnv(launcher, + (const gchar *const *)s->args->= pdata, + &error); + g_object_unref(launcher); + + if (!daemon) { + error_setg(errp, "Error creating daemon: %s", error->message); + return -1; + } + + if (!g_subprocess_wait(daemon, NULL, &error)) { + error_setg(errp, "Error waiting for daemon: %s", error->message); + return -1; + } + + if (g_subprocess_get_if_exited(daemon) && + g_subprocess_get_exit_status(daemon)) { + return -1; + } + + if (!g_file_get_contents(s->pidfile, &contents, NULL, &error)) { + error_setg(errp, "Cannot read passt pid: %s", error->message); + return -1; + } + + s->pid =3D (pid_t)g_ascii_strtoll(contents, NULL, 10); + if (s->pid <=3D 0) { + error_setg(errp, "File '%s' did not contain a valid PID.", s->pidf= ile); + return -1; + } + + return 0; +} + +static int net_passt_stream_start(NetPasstState *s, Error **errp) +{ + QIOChannelSocket *sioc; + SocketAddress *addr; + int sv[2]; + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) =3D=3D -1) { + error_setg_errno(errp, errno, "socketpair() failed"); + return -1; + } + + /* connect to passt */ + qemu_set_info_str(&s->data.nc, "connecting to passt"); + + /* create socket channel */ + sioc =3D qio_channel_socket_new(); + s->data.ioc =3D QIO_CHANNEL(sioc); + s->data.nc.link_down =3D true; + s->data.send =3D net_passt_send; + + addr =3D g_new0(SocketAddress, 1); + addr->type =3D SOCKET_ADDRESS_TYPE_FD; + addr->u.fd.str =3D g_strdup_printf("%d", sv[0]); + + qio_channel_socket_connect_async(sioc, addr, + net_passt_client_connected, s, + NULL, NULL); + + qapi_free_SocketAddress(addr); + + /* start passt */ + if (net_passt_start_daemon(s, sv[1], errp) =3D=3D -1) { + close(sv[0]); + close(sv[1]); + return -1; + } + close(sv[1]); + + return 0; +} + +static int net_passt_vhost_user_init(NetPasstState *s, Error **errp) + +{ + error_setg(errp, "vhost-user parameter not yet implemented"); + + return -1; +} + +static GPtrArray *net_passt_decode_args(const NetDevPasstOptions *passt, + gchar *pidfile, Error **errp) +{ + GPtrArray *args =3D g_ptr_array_new_with_free_func(g_free); + + if (passt->path) { + g_ptr_array_add(args, g_strdup(passt->path)); + } else { + g_ptr_array_add(args, g_strdup("passt")); + } + + /* provide a pid file to be able to kil passt on exit */ + g_ptr_array_add(args, g_strdup("--pid")); + g_ptr_array_add(args, g_strdup(pidfile)); + + /* g_subprocess_launcher_take_fd() will set the socket on fd 3 */ + g_ptr_array_add(args, g_strdup("--fd")); + g_ptr_array_add(args, g_strdup("3")); + + /* by default, be quiet */ + if (!passt->has_quiet || passt->quiet) { + g_ptr_array_add(args, g_strdup("--quiet")); + } + + if (passt->has_debug && passt->debug) { + g_ptr_array_add(args, g_strdup("--debug")); + } + + if (passt->has_trace && passt->trace) { + g_ptr_array_add(args, g_strdup("--trace")); + } + + if (passt->has_vhost_user && passt->vhost_user) { + g_ptr_array_add(args, g_strdup("--vhost-user")); + } + + if (passt->pcap_file) { + g_ptr_array_add(args, g_strdup("--pcap")); + g_ptr_array_add(args, g_strdup(passt->pcap_file)); + } + + if (passt->has_mtu) { + g_ptr_array_add(args, g_strdup("--mtu")); + g_ptr_array_add(args, g_strdup_printf("%"PRId64, passt->mtu)); + } + + if (passt->address) { + g_ptr_array_add(args, g_strdup("--address")); + g_ptr_array_add(args, g_strdup(passt->address)); + } + + if (passt->netmask) { + g_ptr_array_add(args, g_strdup("--netmask")); + g_ptr_array_add(args, g_strdup(passt->netmask)); + } + + if (passt->mac) { + g_ptr_array_add(args, g_strdup("--mac-addr")); + g_ptr_array_add(args, g_strdup(passt->mac)); + } + + if (passt->gateway) { + g_ptr_array_add(args, g_strdup("--gateway")); + g_ptr_array_add(args, g_strdup(passt->gateway)); + } + + if (passt->interface) { + g_ptr_array_add(args, g_strdup("--interface")); + g_ptr_array_add(args, g_strdup(passt->interface)); + } + + if (passt->outbound) { + g_ptr_array_add(args, g_strdup("--outbound")); + g_ptr_array_add(args, g_strdup(passt->outbound)); + } + + if (passt->outbound_if4) { + g_ptr_array_add(args, g_strdup("--outbound-if4")); + g_ptr_array_add(args, g_strdup(passt->outbound_if4)); + } + + if (passt->outbound_if6) { + g_ptr_array_add(args, g_strdup("--outbound-if6")); + g_ptr_array_add(args, g_strdup(passt->outbound_if6)); + } + + if (passt->dns) { + g_ptr_array_add(args, g_strdup("--dns")); + g_ptr_array_add(args, g_strdup(passt->dns)); + } + + if (passt->fqdn) { + g_ptr_array_add(args, g_strdup("--fqdn")); + g_ptr_array_add(args, g_strdup(passt->fqdn)); + } + + if (passt->has_dhcp_dns && !passt->dhcp_dns) { + g_ptr_array_add(args, g_strdup("--no-dhcp-dns")); + } + + if (passt->has_dhcp_search && !passt->dhcp_search) { + g_ptr_array_add(args, g_strdup("--no-dhcp-search")); + } + + if (passt->map_host_loopback) { + g_ptr_array_add(args, g_strdup("--map-host-loopback")); + g_ptr_array_add(args, g_strdup(passt->map_host_loopback)); + } + + if (passt->map_guest_addr) { + g_ptr_array_add(args, g_strdup("--map-guest-addr")); + g_ptr_array_add(args, g_strdup(passt->map_guest_addr)); + } + + if (passt->dns_forward) { + g_ptr_array_add(args, g_strdup("--dns-forward")); + g_ptr_array_add(args, g_strdup(passt->dns_forward)); + } + + if (passt->dns_host) { + g_ptr_array_add(args, g_strdup("--dns-host")); + g_ptr_array_add(args, g_strdup(passt->dns_host)); + } + + if (passt->has_tcp && !passt->tcp) { + g_ptr_array_add(args, g_strdup("--no-tcp")); + } + + if (passt->has_udp && !passt->udp) { + g_ptr_array_add(args, g_strdup("--no-udp")); + } + + if (passt->has_icmp && !passt->icmp) { + g_ptr_array_add(args, g_strdup("--no-icmp")); + } + + if (passt->has_dhcp && !passt->dhcp) { + g_ptr_array_add(args, g_strdup("--no-dhcp")); + } + + if (passt->has_ndp && !passt->ndp) { + g_ptr_array_add(args, g_strdup("--no-ndp")); + } + + if (passt->has_dhcpv6 && !passt->dhcpv6) { + g_ptr_array_add(args, g_strdup("--no-dhcpv6")); + } + + if (passt->has_ra && !passt->ra) { + g_ptr_array_add(args, g_strdup("--no-ra")); + } + + if (passt->has_freebind && passt->freebind) { + g_ptr_array_add(args, g_strdup("--freebind")); + } + + if (passt->has_ipv4 && !passt->ipv4) { + g_ptr_array_add(args, g_strdup("--ipv6-only")); + } + + if (passt->has_ipv6 && !passt->ipv6) { + g_ptr_array_add(args, g_strdup("--ipv4-only")); + } + + if (passt->has_search && passt->search) { + const StringList *list =3D passt->search; + GString *domains =3D g_string_new(list->value->str); + + list =3D list->next; + while (list) { + g_string_append(domains, " "); + g_string_append(domains, list->value->str); + list =3D list->next; + } + + g_ptr_array_add(args, g_strdup("--search")); + g_ptr_array_add(args, g_string_free(domains, FALSE)); + } + + if (passt->has_tcp_ports && passt->tcp_ports) { + const StringList *list =3D passt->tcp_ports; + GString *tcp_ports =3D g_string_new(list->value->str); + + list =3D list->next; + while (list) { + g_string_append(tcp_ports, ","); + g_string_append(tcp_ports, list->value->str); + list =3D list->next; + } + + g_ptr_array_add(args, g_strdup("--tcp-ports")); + g_ptr_array_add(args, g_string_free(tcp_ports, FALSE)); + } + + if (passt->has_udp_ports && passt->udp_ports) { + const StringList *list =3D passt->udp_ports; + GString *udp_ports =3D g_string_new(list->value->str); + + list =3D list->next; + while (list) { + g_string_append(udp_ports, ","); + g_string_append(udp_ports, list->value->str); + list =3D list->next; + } + + g_ptr_array_add(args, g_strdup("--udp-ports")); + g_ptr_array_add(args, g_string_free(udp_ports, FALSE)); + } + + g_ptr_array_add(args, NULL); + + return args; +} + +int net_init_passt(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + g_autoptr(GError) error =3D NULL; + NetClientState *nc; + NetPasstState *s; + GPtrArray *args; + gchar *pidfile; + int pidfd; + + assert(netdev->type =3D=3D NET_CLIENT_DRIVER_PASST); + + pidfd =3D g_file_open_tmp("passt-XXXXXX.pid", &pidfile, &error); + if (pidfd =3D=3D -1) { + error_setg(errp, "Failed to create temporary file: %s", error->mes= sage); + return -1; + } + close(pidfd); + + args =3D net_passt_decode_args(&netdev->u.passt, pidfile, errp); + if (args =3D=3D NULL) { + g_free(pidfile); + return -1; + } + + nc =3D qemu_new_net_client(&net_passt_info, peer, "passt", name); + s =3D DO_UPCAST(NetPasstState, data.nc, nc); + + s->args =3D args; + s->pidfile =3D pidfile; + + if (netdev->u.passt.has_vhost_user && netdev->u.passt.vhost_user) { + if (net_passt_vhost_user_init(s, errp) =3D=3D -1) { + qemu_del_net_client(nc); + return -1; + } + + return 0; + } + + if (net_passt_stream_start(s, errp) =3D=3D -1) { + qemu_del_net_client(nc); + return -1; + } + + return 0; +} diff --git a/qapi/net.json b/qapi/net.json index 97ea1839813b..76d7654414f7 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -112,6 +112,125 @@ 'data': { 'str': 'str' } } =20 +## +# @NetDevPasstOptions: +# +# Unprivileged user-mode network connectivity using passt +# +# @path: path to passt binary +# +# @quiet: don't print informational messages +# +# @debug: be verbose +# +# @trace: extra verbose +# +# @vhost-user: enable vhost-user +# +# @pcap-file: log traffic to pcap file +# +# @mtu: assign MTU via DHCP/NDP +# +# @address: IPv4 or IPv6 address +# +# @netmask: IPv4 mask +# +# @mac: source MAC address +# +# @gateway: IPv4 or IPv6 address as gateway +# +# @interface: interface for addresses and routes +# +# @outbound: bind to address as outbound source +# +# @outbound-if4: bind to outbound interface for IPv4 +# +# @outbound-if6: bind to outbound interface for IPv6 +# +# @dns: IPv4 or IPv6 address as DNS +# +# @search: search domains +# +# @fqdn: FQDN to configure client with +# +# @dhcp-dns: enable/disable DNS list in DHCP/DHCPv6/NDP +# +# @dhcp-search: enable/disable list in DHCP/DHCPv6/NDP +# +# @map-host-loopback: addresse to refer to host +# +# @map-guest-addr: addr to translate to guest's address +# +# @dns-forward: forward DNS queries sent to +# +# @dns-host: host nameserver to direct queries to +# +# @tcp: enable/disable TCP +# +# @udp: enable/disable UDP +# +# @icmp: enable/disable ICMP +# +# @dhcp: enable/disable DHCP +# +# @ndp: enable/disable NDP +# +# @dhcpv6: enable/disable DHCPv6 +# +# @ra: enable/disable route advertisements +# +# @freebind: bind to any address for forwarding +# +# @ipv4: enable/disable IPv4 +# +# @ipv6: enable/disable IPv6 +# +# @tcp-ports: TCP ports to forward +# +# @udp-ports: UDP ports to forward +# +# Since: 10.1 +## +{ 'struct': 'NetDevPasstOptions', + 'data': { + '*path': 'str', + '*quiet': 'bool', + '*debug': 'bool', + '*trace': 'bool', + '*vhost-user': 'bool', + '*pcap-file': 'str', + '*mtu': 'int', + '*address': 'str', + '*netmask': 'str', + '*mac': 'str', + '*gateway': 'str', + '*interface': 'str', + '*outbound': 'str', + '*outbound-if4': 'str', + '*outbound-if6': 'str', + '*dns': 'str', + '*search': ['String'], + '*fqdn': 'str', + '*dhcp-dns': 'bool', + '*dhcp-search': 'bool', + '*map-host-loopback': 'str', + '*map-guest-addr': 'str', + '*dns-forward': 'str', + '*dns-host': 'str', + '*tcp': 'bool', + '*udp': 'bool', + '*icmp': 'bool', + '*dhcp': 'bool', + '*ndp': 'bool', + '*dhcpv6': 'bool', + '*ra': 'bool', + '*freebind': 'bool', + '*ipv4': 'bool', + '*ipv6': 'bool', + '*tcp-ports': ['String'], + '*udp-ports': ['String'] }, + 'if': 'CONFIG_PASST' } + ## # @NetdevUserOptions: # @@ -729,12 +848,15 @@ # # @af-xdp: since 8.2 # +# @passt: since 10.1 +# # Since: 2.7 ## { 'enum': 'NetClientDriver', 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'stream', 'dgram', 'vde', 'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa', + { 'name': 'passt', 'if': 'CONFIG_PASST' }, { 'name': 'af-xdp', 'if': 'CONFIG_AF_XDP' }, { 'name': 'vmnet-host', 'if': 'CONFIG_VMNET' }, { 'name': 'vmnet-shared', 'if': 'CONFIG_VMNET' }, @@ -756,6 +878,8 @@ 'discriminator': 'type', 'data': { 'nic': 'NetLegacyNicOptions', + 'passt': { 'type': 'NetDevPasstOptions', + 'if': 'CONFIG_PASST' }, 'user': 'NetdevUserOptions', 'tap': 'NetdevTapOptions', 'l2tpv3': 'NetdevL2TPv3Options', diff --git a/qemu-options.hx b/qemu-options.hx index 1f862b19a676..4787f9309c69 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2796,6 +2796,18 @@ DEFHEADING() DEFHEADING(Network options:) =20 DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, +#ifdef CONFIG_PASST + "-netdev passt,id=3Dstr[,path=3Dfile][,quiet=3Don|off][,debug=3Don|off= ][,trace=3Don|off]\n" + " [,vhost-user=3Don|off][,pcap-file=3Dfile][,mtu=3Dmtu]\n" + " [,address=3Daddr][,netmask=3Dmask][,mac=3Daddr][,gateway=3D= addr]\n" + " [,interface=3Dname][,outbound=3Daddress][,outbound-if4=3Dna= me]\n" + " [,outbound-if6=3Dname][,dns=3Daddr][,search=3Dlist][,fqdn= =3Dname]\n" + " [,dhcp-dns=3Don|off][,dhcp-search=3Don|off][,map-host-loopb= ack=3Daddr]\n" + " [,map-guest-addr=3Daddr][,dns-forward=3Daddr][,dns-host=3Da= ddr]\n" + " [,tcp=3Don|off][,udp=3Don|off][,icmp=3Don|off][,dhcp=3Don|o= ff]\n" + " [,ndp=3Don|off][,dhcpv6=3Don|off][,ra=3Don|off][,freebind= =3Don|off]\n" + " [,ipv4=3Don|off][,ipv6=3Don|off][,tcp-ports=3Dspec][,udp-po= rts=3Dspec]\n" +#endif #ifdef CONFIG_SLIRP "-netdev user,id=3Dstr[,ipv4=3Don|off][,net=3Daddr[/mask]][,host=3Dadd= r]\n" " [,ipv6=3Don|off][,ipv6-net=3Daddr[/int]][,ipv6-host=3Daddr]\= n" @@ -2952,6 +2964,9 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, " configure a hub port on the hub with ID 'n'\n", QEMU_= ARCH_ALL) DEF("nic", HAS_ARG, QEMU_OPTION_nic, "-nic [tap|bridge|" +#ifdef CONFIG_PASST + "passt|" +#endif #ifdef CONFIG_SLIRP "user|" #endif @@ -2984,6 +2999,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net, " configure or create an on-board (or machine default) = NIC and\n" " connect it to hub 0 (please use -nic unless you need = a hub)\n" "-net [" +#ifdef CONFIG_PASST + "passt|" +#endif #ifdef CONFIG_SLIRP "user|" #endif --=20 2.49.0 From nobody Sat Nov 15 14:11:15 2025 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=quarantine dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1750262320; cv=none; d=zohomail.com; s=zohoarc; b=BD7EODBM2AKTdbt4ztWeWiRVjUk7RwRmmzgD/dEQYzM0KSHqVq0HU1NvE4LGY25KuojhWi2sRyH7YdaCHznzYnHkqMAk8wGi8Ym47zA8DA1G9q/JHPBf7bDy6lbZCyFeE5ys9uLvbi082gJpBwfHlvJRj5w1Eb0OmUj5mvrGycA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750262320; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=XjOKQq/HtHX0Q+fp7uuUuYDKpD2d+b8aaEwEDRrmmLk=; b=YMAwQZZnSbanCiJVCFL3yn56bEpOBCAQZELEgDHFo9mPrduafGiSnGlDGhzhF3ssqi9qg5qXdXfZT2sV0itDoljOvbuRxFVAP5bH7r88bEnp1R2xpqC3KfitkpuE/Zhv5BoX7f59l3iYMEZkoyNuPfsI8/deCPNQ9b0OLEqJe+w= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1750262320293161.79839137058968; Wed, 18 Jun 2025 08:58:40 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRvBF-0003RK-MX; Wed, 18 Jun 2025 11:58:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvB0-0003KF-Rw for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:58:16 -0400 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1uRvAx-0008CX-Mg for qemu-devel@nongnu.org; Wed, 18 Jun 2025 11:58:13 -0400 Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-649-ZyoSGCBuMoesF1i3SO6ITA-1; Wed, 18 Jun 2025 11:58:09 -0400 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1CBDC1809C8B; Wed, 18 Jun 2025 15:58:08 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7419F18003FC; Wed, 18 Jun 2025 15:58:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750262290; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XjOKQq/HtHX0Q+fp7uuUuYDKpD2d+b8aaEwEDRrmmLk=; b=jQjhBndHd41+OSoCq+US2QHAkmfwr5ddp+c5HINI3/bHYu8v58B478nBUrmpvontbvP+xS rudg1vRodwfY8vIBVlTolNwkhm8xQGr4bCRFztwI/JymTRH1joRCCR6TYWmXYiBjcq/uBI G7Pe/oKKpEGJciUpsitI8OGZsvXN2Do= X-MC-Unique: ZyoSGCBuMoesF1i3SO6ITA-1 X-Mimecast-MFC-AGG-ID: ZyoSGCBuMoesF1i3SO6ITA_1750262288 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Markus Armbruster , Stefan Weil , Stefano Garzarella , Jason Wang , "Michael S. Tsirkin" , "Dr. David Alan Gilbert" , Eric Blake , Paolo Bonzini , Laurent Vivier Subject: [PATCH v2 10/10] net/passt: Implement vhost-user backend support Date: Wed, 18 Jun 2025 17:57:18 +0200 Message-ID: <20250618155718.550968-11-lvivier@redhat.com> In-Reply-To: <20250618155718.550968-1-lvivier@redhat.com> References: <20250618155718.550968-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.93 Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -39 X-Spam_score: -4.0 X-Spam_bar: ---- X-Spam_report: (-4.0 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-1.895, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H5=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1750262321788116600 Content-Type: text/plain; charset="utf-8" This commit adds support for the vhost-user interface to the passt network backend, enabling high-performance, accelerated networking for guests using passt. The passt backend can now operate in a vhost-user mode, where it communicates with the guest's virtio-net device over a socket pair using the vhost-user protocol. This offloads the datapath from the main QEMU loop, significantly improving network performance. The implementation involves: - Extending NetPasstState to manage the vhost-user connection state, including the chardev frontend and the vhost_net instance. - Adding the full vhost-user connection and event handling logic, similar to the standalone net/vhost-user.c client. - Populating the NetClientInfo structure with implementations for all the required vhost callbacks that were recently refactored (is_vhost_user, get_vhost_net, save_acked_features, etc). When the vhost-user=3Don option is used with -netdev passt, the new vhost initialization path is taken instead of the standard stream-based connection. Signed-off-by: Laurent Vivier --- net/passt.c | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) diff --git a/net/passt.c b/net/passt.c index ce194b1e02f0..3c6bc0dfe89f 100644 --- a/net/passt.c +++ b/net/passt.c @@ -7,18 +7,75 @@ */ #include "qemu/osdep.h" #include +#include "qemu/error-report.h" #include #include "net/net.h" #include "clients.h" #include "qapi/error.h" #include "io/net-listener.h" +#include "chardev/char-fe.h" +#include "net/vhost_net.h" +#include "hw/virtio/vhost.h" +#include "hw/virtio/vhost-user.h" +#include "standard-headers/linux/virtio_net.h" #include "stream_data.h" =20 +#ifdef CONFIG_VHOST_USER +static const int user_feature_bits[] =3D { + VIRTIO_F_NOTIFY_ON_EMPTY, + VIRTIO_F_NOTIFICATION_DATA, + VIRTIO_RING_F_INDIRECT_DESC, + VIRTIO_RING_F_EVENT_IDX, + + VIRTIO_F_ANY_LAYOUT, + VIRTIO_F_VERSION_1, + VIRTIO_NET_F_CSUM, + VIRTIO_NET_F_GUEST_CSUM, + VIRTIO_NET_F_GSO, + VIRTIO_NET_F_GUEST_TSO4, + VIRTIO_NET_F_GUEST_TSO6, + VIRTIO_NET_F_GUEST_ECN, + VIRTIO_NET_F_GUEST_UFO, + VIRTIO_NET_F_HOST_TSO4, + VIRTIO_NET_F_HOST_TSO6, + VIRTIO_NET_F_HOST_ECN, + VIRTIO_NET_F_HOST_UFO, + VIRTIO_NET_F_MRG_RXBUF, + VIRTIO_NET_F_MTU, + VIRTIO_F_IOMMU_PLATFORM, + VIRTIO_F_RING_PACKED, + VIRTIO_F_RING_RESET, + VIRTIO_F_IN_ORDER, + VIRTIO_NET_F_RSS, + VIRTIO_NET_F_RSC_EXT, + VIRTIO_NET_F_HASH_REPORT, + VIRTIO_NET_F_GUEST_USO4, + VIRTIO_NET_F_GUEST_USO6, + VIRTIO_NET_F_HOST_USO, + + /* This bit implies RARP isn't sent by QEMU out of band */ + VIRTIO_NET_F_GUEST_ANNOUNCE, + + VIRTIO_NET_F_MQ, + + VHOST_INVALID_FEATURE_BIT +}; +#endif + typedef struct NetPasstState { NetStreamData data; GPtrArray *args; gchar *pidfile; pid_t pid; +#ifdef CONFIG_VHOST_USER + /* vhost user */ + VhostUserState *vhost_user; + VHostNetState *vhost_net; + CharBackend vhost_chr; + guint vhost_watch; + uint64_t acked_features; + bool started; +#endif } NetPasstState; =20 static int net_passt_stream_start(NetPasstState *s, Error **errp); @@ -27,6 +84,24 @@ static void net_passt_cleanup(NetClientState *nc) { NetPasstState *s =3D DO_UPCAST(NetPasstState, data.nc, nc); =20 +#ifdef CONFIG_VHOST_USER + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); + s->vhost_net =3D NULL; + } + if (s->vhost_watch) { + g_source_remove(s->vhost_watch); + s->vhost_watch =3D 0; + } + qemu_chr_fe_deinit(&s->vhost_chr, true); + if (s->vhost_user) { + vhost_user_cleanup(s->vhost_user); + g_free(s->vhost_user); + s->vhost_user =3D NULL; + } +#endif + kill(s->pid, SIGTERM); g_remove(s->pidfile); g_free(s->pidfile); @@ -60,11 +135,112 @@ static gboolean net_passt_send(QIOChannel *ioc, GIOCo= ndition condition, return G_SOURCE_CONTINUE; } =20 +#ifdef CONFIG_VHOST_USER +static int passt_set_vnet_endianness(NetClientState *nc, bool enable) +{ + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_PASST); + + return 0; +} + +static bool passt_has_vnet_hdr(NetClientState *nc) +{ + NetPasstState *s =3D DO_UPCAST(NetPasstState, data.nc, nc); + + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_PASST); + + return s->vhost_user !=3D NULL; +} + +static bool passt_has_ufo(NetClientState *nc) +{ + NetPasstState *s =3D DO_UPCAST(NetPasstState, data.nc, nc); + + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_PASST); + + return s->vhost_user !=3D NULL; +} + +static bool passt_check_peer_type(NetClientState *nc, ObjectClass *oc, + Error **errp) +{ + NetPasstState *s =3D DO_UPCAST(NetPasstState, data.nc, nc); + const char *driver =3D object_class_get_name(oc); + + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_PASST); + + if (s->vhost_user !=3D NULL) { + return true; + } + + if (!g_str_has_prefix(driver, "virtio-net-")) { + error_setg(errp, "vhost-user requires frontend driver virtio-net-*= "); + return false; + } + + return true; +} + +static bool passt_is_vhost_user(NetClientState *nc) +{ + NetPasstState *s =3D DO_UPCAST(NetPasstState, data.nc, nc); + + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_PASST); + + return s->vhost_user !=3D NULL; +} + +static struct vhost_net *passt_get_vhost_net(NetClientState *nc) +{ + NetPasstState *s =3D DO_UPCAST(NetPasstState, data.nc, nc); + + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_PASST); + + return s->vhost_net; +} + +static uint64_t passt_get_acked_features(NetClientState *nc) +{ + NetPasstState *s =3D DO_UPCAST(NetPasstState, data.nc, nc); + + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_PASST); + + return s->acked_features; +} + +static void passt_save_acked_features(NetClientState *nc) +{ + NetPasstState *s =3D DO_UPCAST(NetPasstState, data.nc, nc); + + assert(nc->info->type =3D=3D NET_CLIENT_DRIVER_PASST); + + if (s->vhost_net) { + uint64_t features =3D vhost_net_get_acked_features(s->vhost_net); + if (features) { + s->acked_features =3D features; + } + } +} +#endif + static NetClientInfo net_passt_info =3D { .type =3D NET_CLIENT_DRIVER_PASST, .size =3D sizeof(NetPasstState), .receive =3D net_passt_receive, .cleanup =3D net_passt_cleanup, +#ifdef CONFIG_VHOST_USER + .has_vnet_hdr =3D passt_has_vnet_hdr, + .has_ufo =3D passt_has_ufo, + .set_vnet_be =3D passt_set_vnet_endianness, + .set_vnet_le =3D passt_set_vnet_endianness, + .check_peer_type =3D passt_check_peer_type, + .is_vhost_user =3D passt_is_vhost_user, + .get_vhost_net =3D passt_get_vhost_net, + .vhost_feature_bits =3D user_feature_bits, + .get_acked_features =3D passt_get_acked_features, + .save_acked_features =3D passt_save_acked_features, + .max_tx_queue_size =3D VIRTQUEUE_MAX_SIZE, +#endif }; =20 static void net_passt_client_connected(QIOTask *task, gpointer opaque) @@ -163,13 +339,171 @@ static int net_passt_stream_start(NetPasstState *s, = Error **errp) return 0; } =20 +#ifdef CONFIG_VHOST_USER +static gboolean passt_vhost_user_watch(void *do_not_use, GIOCondition cond, + void *opaque) +{ + NetPasstState *s =3D opaque; + + qemu_chr_fe_disconnect(&s->vhost_chr); + + return G_SOURCE_CONTINUE; +} + +static void passt_vhost_user_event(void *opaque, QEMUChrEvent event); + +static void chr_closed_bh(void *opaque) +{ + NetPasstState *s =3D opaque; + + passt_save_acked_features(&s->data.nc); + + net_client_set_link(&(NetClientState *){ &s->data.nc }, 1, false); + + qemu_chr_fe_set_handlers(&s->vhost_chr, NULL, NULL, passt_vhost_user_e= vent, + NULL, s, NULL, true); +} + +static void passt_vhost_user_stop(NetPasstState *s) +{ + passt_save_acked_features(&s->data.nc); + vhost_net_cleanup(s->vhost_net); +} + +static int passt_vhost_user_start(NetPasstState *s, VhostUserState *be) +{ + struct vhost_net *net =3D NULL; + VhostNetOptions options; + + options.backend_type =3D VHOST_BACKEND_TYPE_USER; + options.net_backend =3D &s->data.nc; + options.opaque =3D be; + options.busyloop_timeout =3D 0; + options.nvqs =3D 2; + + net =3D vhost_net_init(&options); + if (!net) { + error_report("failed to init passt vhost_net"); + goto err; + } + + if (s->vhost_net) { + vhost_net_cleanup(s->vhost_net); + g_free(s->vhost_net); + } + s->vhost_net =3D net; + + return 0; +err: + if (net) { + vhost_net_cleanup(net); + g_free(net); + } + passt_vhost_user_stop(s); + return -1; +} + +static void passt_vhost_user_event(void *opaque, QEMUChrEvent event) +{ + NetPasstState *s =3D opaque; + Error *err =3D NULL; + + switch (event) { + case CHR_EVENT_OPENED: + if (passt_vhost_user_start(s, s->vhost_user) < 0) { + qemu_chr_fe_disconnect(&s->vhost_chr); + return; + } + s->vhost_watch =3D qemu_chr_fe_add_watch(&s->vhost_chr, G_IO_HUP, + passt_vhost_user_watch, s); + net_client_set_link(&(NetClientState *){ &s->data.nc }, 1, true); + s->started =3D true; + break; + case CHR_EVENT_CLOSED: + if (s->vhost_watch) { + AioContext *ctx =3D qemu_get_current_aio_context(); + + g_source_remove(s->vhost_watch); + s->vhost_watch =3D 0; + qemu_chr_fe_set_handlers(&s->vhost_chr, NULL, NULL, NULL, NUL= L, + NULL, NULL, false); + + aio_bh_schedule_oneshot(ctx, chr_closed_bh, s); + } + break; + case CHR_EVENT_BREAK: + case CHR_EVENT_MUX_IN: + case CHR_EVENT_MUX_OUT: + /* Ignore */ + break; + } + + if (err) { + error_report_err(err); + } +} + static int net_passt_vhost_user_init(NetPasstState *s, Error **errp) +{ + Chardev *chr; + int sv[2]; + + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) =3D=3D -1) { + error_setg_errno(errp, errno, "socketpair() failed"); + return -1; + } + + /* connect to passt */ + qemu_set_info_str(&s->data.nc, "connecting to passt"); + + /* create chardev */ + + chr =3D CHARDEV(object_new(TYPE_CHARDEV_SOCKET)); + if (!chr || qemu_chr_add_client(chr, sv[0]) =3D=3D -1) { + object_unref(OBJECT(chr)); + error_setg(errp, "Failed to make socket chardev"); + goto err; + } + + s->vhost_user =3D g_new0(struct VhostUserState, 1); + if (!qemu_chr_fe_init(&s->vhost_chr, chr, errp) || + !vhost_user_init(s->vhost_user, &s->vhost_chr, errp)) { + goto err; + } + + /* start passt */ + if (net_passt_start_daemon(s, sv[1], errp) =3D=3D -1) { + goto err; + } + + do { + if (qemu_chr_fe_wait_connected(&s->vhost_chr, errp) < 0) { + goto err; + } + + qemu_chr_fe_set_handlers(&s->vhost_chr, NULL, NULL, + passt_vhost_user_event, NULL, s, NULL, + true); + } while (!s->started); =20 + qemu_set_info_str(&s->data.nc, "vhost-user,connected to pid %d", s->pi= d); + + close(sv[1]); + return 0; +err: + close(sv[0]); + close(sv[1]); + + return -1; +} +#else +static int net_passt_vhost_user_init(NetPasstState *s, Error **errp) { error_setg(errp, "vhost-user parameter not yet implemented"); =20 return -1; } +#endif =20 static GPtrArray *net_passt_decode_args(const NetDevPasstOptions *passt, gchar *pidfile, Error **errp) --=20 2.49.0