From nobody Sat Nov 15 14:49:49 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=1750236167; cv=none; d=zohomail.com; s=zohoarc; b=nMhC0M8SKyiSPwksuZz7y/KOsqAE819UkK0xI+btth2VlhdwOUUwGxSMLtqNY6wgkFXPa5+nS5RSr3Z2c3esPA6n/KGOtGzVTZ1XxVdQB5PncY0YoME4vskOY8R9APhCZV+C6M2rwwuRC+VafO/9ecxKbZFMHDsH0Ed2yiWLF5g= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750236167; 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=fsZj8vt48Cx4aPNMwBQw4C3D9RrzCQUDlMhTO2l7rRE=; b=PozzwvrCTV7XX2bx+CDUUSDYBH9X+rnEaN2ABi7blc6zbTcSlRXHK+OMjwwUmMaFCD2tn0WiYL/d2fVZZpG3BYzZPtJJZ5y27FiA5gawHwjoGBrDZ5pZdH564vfWQJG3zcmhCU2gqAhLhpE6LnZ0pkYqVYHdt5cms9zTnjgaRk0= 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 17502361672197.3520648369208175; Wed, 18 Jun 2025 01:42:47 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRoMP-0005qC-6z; Wed, 18 Jun 2025 04:41:33 -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 1uRoM5-0005k4-Al for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41:14 -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 1uRoM2-0002aM-45 for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41:13 -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-186-V9B3J4a-P3qorR2FsY6GUw-1; Wed, 18 Jun 2025 04:39:42 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 5B7B71800286; Wed, 18 Jun 2025 08:39:41 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E2E7019560A3; Wed, 18 Jun 2025 08:39:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750236061; 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=fsZj8vt48Cx4aPNMwBQw4C3D9RrzCQUDlMhTO2l7rRE=; b=ie+0S99+89LMTT2ER+I8KUkb4UNxeJm1CocKASrpNM0bPY/Q2vTzFBupwgd9aLx6leBBjk nMWiYHXobUs4EC75XIWK5Eqkb5gngQwj1zjCO4N56bBfgk9mtXPJ2Z8kEx93JPBRkA3WZm peFA02w6mR4+dGouuayp3eivNmIN0gk= X-MC-Unique: V9B3J4a-P3qorR2FsY6GUw-1 X-Mimecast-MFC-AGG-ID: V9B3J4a-P3qorR2FsY6GUw_1750235981 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Paolo Bonzini , "Michael S. Tsirkin" , Eric Blake , Stefano Garzarella , Stefan Weil , Jason Wang , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , "Dr. David Alan Gilbert" , Markus Armbruster , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Laurent Vivier Subject: [PATCH 1/8] net: Refactor stream logic for reuse in '-net passt' Date: Wed, 18 Jun 2025 10:39:23 +0200 Message-ID: <20250618083930.451313-2-lvivier@redhat.com> In-Reply-To: <20250618083930.451313-1-lvivier@redhat.com> References: <20250618083930.451313-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 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.89, 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: 1750236170134116600 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 Tested-by: Lei Yang --- 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 4de56138445c..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; - 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..bb52bef9d5aa --- /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; + 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:49:49 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=1750236116; cv=none; d=zohomail.com; s=zohoarc; b=e8ChNDtvV02b+H2GgnaYRfjBWM34kTCT9Dw4EiOwRUVm3vORw3TKMWNioVC6mjZNZw5v84A7vsA4ZtBb5oJWjQlTZ0ULWCu5Pm3Z+vTLMihiWxmIdQtecZftIFolB6QBsOtceDfxk+aYpqo9pDuf13FrvC2PKF3LPTYqi555FiA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750236116; 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=M4pIWZa2SidezN38lJcOf4jF4BK8oTKx6FVmshfXnRZGum3LBmc+G1oc71IrcC1qZyollr4UZ5LhP7TAcT5GTajhNurbmBXLSjtprO9f3Hk/wuHV8FW9cZas3HntxvisRoU8qZX5iSpokxaaWDxAD6+L4fK9L37BLO2QX2gEeis= 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 17502361169661003.9620863410136; Wed, 18 Jun 2025 01:41:56 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRoM7-0005kM-Eo; Wed, 18 Jun 2025 04:41:15 -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 1uRoM3-0005jq-Px for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41:11 -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 1uRoM0-0002a9-1E for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41: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-344-On_cWLyoNsGYc7bPfmB5xw-1; Wed, 18 Jun 2025 04:39:47 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 4DA7B18002ED; Wed, 18 Jun 2025 08:39:46 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D6F9919560A3; Wed, 18 Jun 2025 08:39:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750236060; 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=JbvNKcK9H49lQ9akJnfxyp+h324Eq+MRYHfRMB9qI59E4mh0uHmZAJazLlhUStnyoMr3fp ACvgEXLmm4VLqvlylGdJAKc3fRxtXrsQ+syg6oW19FqQvj9A77HNtcRjJR7jufzTCFAVqp T2Qwes9d8EIY166VNbMMl+ldscWV7Lc= X-MC-Unique: On_cWLyoNsGYc7bPfmB5xw-1 X-Mimecast-MFC-AGG-ID: On_cWLyoNsGYc7bPfmB5xw_1750235986 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Paolo Bonzini , "Michael S. Tsirkin" , Eric Blake , Stefano Garzarella , Stefan Weil , Jason Wang , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , "Dr. David Alan Gilbert" , Markus Armbruster , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Laurent Vivier Subject: [PATCH 2/8] net: Define net_client_set_link() Date: Wed, 18 Jun 2025 10:39:24 +0200 Message-ID: <20250618083930.451313-3-lvivier@redhat.com> In-Reply-To: <20250618083930.451313-1-lvivier@redhat.com> References: <20250618083930.451313-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 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.89, 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: 1750236118030116600 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 Tested-by: Lei Yang --- 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:49:49 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=1750236116; cv=none; d=zohomail.com; s=zohoarc; b=ZF7WkbXBOLCZvCrNVXfWUzSNyAJZOcAQLLsqPDAoWTi+arra97zNa+jorS7SqCz4UcDRO+Kt5+cqeQXS6Ba4ov9po5QUm62RR3FPRdufHP7cwJreALW1Ryw1WvoPb0uoDgcduwMFtey0h5Yo+CFwqh1GDGyyJ9tIBEfUYarJO08= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750236116; 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=JpoESKiiI1Pf52xnsFbE2a8bgaW+GSdR3SgxO0yJUas=; b=FyEz0mNMiuXAifi5q/p9w5yhvZM0mSvBq7jS3SzTItu9yNXn89KppLX4nk+Mmm98B9q6sDb90ylVXhy9eeT16BpCSs1mDnIFganCcw7yvySUGLaBiSbNrxg9LkY8dPPbzIYY2pE6kkwUbLubJ8BmKmuu3ytLNkS/KVGINekKzDQ= 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 1750236116957384.1075070219897; Wed, 18 Jun 2025 01:41:56 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRoML-0005nw-Uw; Wed, 18 Jun 2025 04:41:30 -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 1uRoM5-0005kC-GI for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41:14 -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 1uRoM2-0002aK-2k for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41:13 -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-281-RucAslPeOmiQ4nPvyDdAwQ-1; Wed, 18 Jun 2025 04:39:52 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 0FE5018002A0; Wed, 18 Jun 2025 08:39:51 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id C82FC19560A3; Wed, 18 Jun 2025 08:39:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750236061; 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=JpoESKiiI1Pf52xnsFbE2a8bgaW+GSdR3SgxO0yJUas=; b=ZK4WPwsfxUq6efNdT9Pcz0E1MTYt8s2hCQYtXgmx3hNrGCWOmVu+uLJ8gr5MAhFSF6dfZT ZIyvK3X8KWfajr3uLb0gRSibnlWk0rDxQTLMM/Eug5ikwWWRNF4cl27m/OlZheYxeWKHAT Bg19XopowjIUEgkcSB+btPQMPG0RZRs= X-MC-Unique: RucAslPeOmiQ4nPvyDdAwQ-1 X-Mimecast-MFC-AGG-ID: RucAslPeOmiQ4nPvyDdAwQ_1750235991 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Paolo Bonzini , "Michael S. Tsirkin" , Eric Blake , Stefano Garzarella , Stefan Weil , Jason Wang , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , "Dr. David Alan Gilbert" , Markus Armbruster , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Laurent Vivier Subject: [PATCH 3/8] net: Introduce helper to identify vhost-user clients Date: Wed, 18 Jun 2025 10:39:25 +0200 Message-ID: <20250618083930.451313-4-lvivier@redhat.com> In-Reply-To: <20250618083930.451313-1-lvivier@redhat.com> References: <20250618083930.451313-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 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.89, 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: 1750236118106116600 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 Tested-by: Lei Yang --- 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 221252e00a50..abb5e5a9860d 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:49:49 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=1750236154; cv=none; d=zohomail.com; s=zohoarc; b=BFKWyGR+r5bfRzPkavkzAkNmFXNQgBbKRT/m9T5yblFO8XxbotDmQdw0yT2e8BJFCzRhdhO58LzuNcE8FnkEH5uxCoS+W0e8xfA5ptZlm4u4/aesZrOrWckNXnnNpLiStu4bOjCVYrPbLUFsYnpyIdzQBYYysrCfzBvHJsY1oy8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750236154; 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=YpbN8liGwHOfuqyRDvGFtRCk/5PttX056L8La+NN4rxPh4MMvSAoesDtb7Jd43RoS9LiLIhOi0MjNJPNg5eoQ29RqLHL7dBBvsJtfz8nHqx27+eOaf80iitbBYyduUyE6amMeZfWPL2g7ynIr+6hEzcNAG7gDzy8wqf0aH4/hAA= 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 1750236154748694.0255301371419; Wed, 18 Jun 2025 01:42:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRoMy-0007I9-0h; Wed, 18 Jun 2025 04:42:08 -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 1uRoMv-0007Ej-CS for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:42: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 1uRoMs-000355-5J for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:42:05 -0400 Received: from mx-prod-mc-04.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-17-vBAub8AOPyComycXb_dRoQ-1; Wed, 18 Jun 2025 04:39:56 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D5A6C19560AA; Wed, 18 Jun 2025 08:39:55 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 8BB7619560A3; Wed, 18 Jun 2025 08:39:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750236121; 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=ChRS6E+zSrKynXFb+0E3FnDYd48jIBoloX9tdDVPE7jyqG0fdoAmIr+9mXq56kCe4r10bL 0COuEyInDdd+lQ74hCC5mQ0h7Im49lWaibz9w11+CHEEUOJUrTwjQdTotLTX75AZnOvBda I7ZmEut693vM8vsuWi9yo0vfv3rNgWo= X-MC-Unique: vBAub8AOPyComycXb_dRoQ-1 X-Mimecast-MFC-AGG-ID: vBAub8AOPyComycXb_dRoQ_1750235996 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Paolo Bonzini , "Michael S. Tsirkin" , Eric Blake , Stefano Garzarella , Stefan Weil , Jason Wang , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , "Dr. David Alan Gilbert" , Markus Armbruster , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Laurent Vivier Subject: [PATCH 4/8] net: Add get_vhost_net callback to NetClientInfo Date: Wed, 18 Jun 2025 10:39:26 +0200 Message-ID: <20250618083930.451313-5-lvivier@redhat.com> In-Reply-To: <20250618083930.451313-1-lvivier@redhat.com> References: <20250618083930.451313-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 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.89, 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: 1750236155932116600 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 Tested-by: Lei Yang --- 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:49:49 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=1750236148; cv=none; d=zohomail.com; s=zohoarc; b=VsxzRmkV4hgsDKPeD80M9pAtEFPNQmFm5WLChv/QB6aTsrw8DUP8UOOQX5uwosW3M8aY37Bw+HImM39k7WBvHsJL8Of0OKXsUnsOLiGKyCaySc0UtIKvhEDjfqAd7FR4HHU9Ej0Cy1jX0b3EQ6Lr12DYVhL9ytriy7gH4NpaM84= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750236148; 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=LW4woBf+JYgEkIBxPOdruLdmgq/fFn7cED5G8WWo9yw=; b=GEZ1rO6a2foDuwnk/O0gZ5cqwDNVEdZDQma+xxNqSlBhHWVPu4aEZ29Q7mnJhtSZ+CHvqrAfWHUXSPy+RNbMpDRrY+mCuHheuYKccH+wWYAuy6AGJhcSvSZku5oRzfMmg2AKqndcZkwKX/mWAVre61lgqYnh6VuL12hJqM756Mk= 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 1750236148262395.37297657138254; Wed, 18 Jun 2025 01:42:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRoMO-0005qB-GW; Wed, 18 Jun 2025 04:41:33 -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 1uRoM8-0005kr-Gg for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41: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 1uRoM5-0002bk-9c for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41:16 -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-270-CJUMvmMQPae0h9bh6Zdz7A-1; Wed, 18 Jun 2025 04:40:01 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 665771800287; Wed, 18 Jun 2025 08:40:00 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 5E39E19560A3; Wed, 18 Jun 2025 08:39:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750236072; 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=LW4woBf+JYgEkIBxPOdruLdmgq/fFn7cED5G8WWo9yw=; b=OWt+ovEGe5xj0+W8Xmrm7w34QOpRHJOMCtO6oi1YBnnPDg5a8X5dq1nvzg3Jx6SWYK7s7w ik2i1wADSTuqPfT+5/6gK82K9hq8q4/1UrNqpTNScoxea9sHiKqavd6pjzHuRgoKwTQ1ne 7ob2cUvOEZ/aYQuA54l0dqQCMxO6N8M= X-MC-Unique: CJUMvmMQPae0h9bh6Zdz7A-1 X-Mimecast-MFC-AGG-ID: CJUMvmMQPae0h9bh6Zdz7A_1750236000 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Paolo Bonzini , "Michael S. Tsirkin" , Eric Blake , Stefano Garzarella , Stefan Weil , Jason Wang , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , "Dr. David Alan Gilbert" , Markus Armbruster , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Laurent Vivier Subject: [PATCH 5/8] net: Add get_acked_features callback to NetClientInfo Date: Wed, 18 Jun 2025 10:39:27 +0200 Message-ID: <20250618083930.451313-6-lvivier@redhat.com> In-Reply-To: <20250618083930.451313-1-lvivier@redhat.com> References: <20250618083930.451313-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 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.89, 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: 1750236149750116600 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 Tested-by: Lei Yang --- 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 16dadd022e75..4ed28a6d4186 100644 --- a/hw/net/vhost_net.c +++ b/hw/net/vhost_net.c @@ -317,8 +317,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"); @@ -369,17 +369,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 8a62cd6e8aab..ed9febd378b6 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; @@ -96,6 +97,7 @@ typedef struct NetClientInfo { NetCheckPeerType *check_peer_type; IsVHostUser *is_vhost_user; GetVHostNet *get_vhost_net; + GetAckedFeatures *get_acked_features; } NetClientInfo; =20 struct NetClientState { @@ -197,6 +199,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 2caa7e56f7a0..45c952b1e76d 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -39,7 +39,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); @@ -240,6 +240,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, + .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:49:49 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=1750236116; cv=none; d=zohomail.com; s=zohoarc; b=Ql02uUbDIYxzSTK9XqBq0KIYk90lARdIvkqJk8A9Q1gIQPIB6Iwq9Gr1d6jFNlEPhY+/AGIks6R7xmAbUj+Emo+qH+eFHGJk7LZlwWPG9jT1iHrS5Iym3IH3Ru+W50WYDLykg/bMp7qoLZ329Aqj9oMkRvVMYm0EIBj6KKxFRcA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750236116; 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=G6+zu2UnX7p4TL7GhSRcCRTo2xWwrAFDUKE6pr4935U=; b=d6DqFKhzC5QetejLMlwwCf/z0W6/U+JNclWp6uRIZdVmoHV9+KMSwEXkkAarpoKX+dZ2toolx3asF/cvkCyRJA8PKqVIfoEq6qhmIouK3GwH2Of84/+v+g6aMmo7gwNMgH+oAVeOQEjOlvYhnvrGZ1idZWyl9aX7fRxScXE6SX0= 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 1750236116908818.926358558933; Wed, 18 Jun 2025 01:41:56 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRoMR-0005rU-98; Wed, 18 Jun 2025 04:41:37 -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 1uRoMJ-0005o6-LW for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41:29 -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 1uRoM8-0002cQ-7b for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:41:17 -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-683-ufZc1lHnP-u1updQuYY5Hg-1; Wed, 18 Jun 2025 04:40:06 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 9BA1318089B4; Wed, 18 Jun 2025 08:40:05 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E326B19560A3; Wed, 18 Jun 2025 08:40:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750236075; 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=G6+zu2UnX7p4TL7GhSRcCRTo2xWwrAFDUKE6pr4935U=; b=LeE8e42T8A4qQdW331GcStF2UkchpSL0XcKR0tqf9C8Bh2TcujJc3PB028plk/F23kPtj9 du54yVy4P9NI3J27GhQCn1UXRb765iiOkys1biIw2RD3ppFbOlRpzLCWZ1h2gHJBJE3v2B GepRCPLJUcRf4XQpj5cNeNvJUxuHJYY= X-MC-Unique: ufZc1lHnP-u1updQuYY5Hg-1 X-Mimecast-MFC-AGG-ID: ufZc1lHnP-u1updQuYY5Hg_1750236005 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Paolo Bonzini , "Michael S. Tsirkin" , Eric Blake , Stefano Garzarella , Stefan Weil , Jason Wang , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , "Dr. David Alan Gilbert" , Markus Armbruster , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Laurent Vivier Subject: [PATCH 6/8] net: Add save_acked_features callback to NetClientInfo Date: Wed, 18 Jun 2025 10:39:28 +0200 Message-ID: <20250618083930.451313-7-lvivier@redhat.com> In-Reply-To: <20250618083930.451313-1-lvivier@redhat.com> References: <20250618083930.451313-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 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.89, 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: 1750236118091116600 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 Tested-by: Lei Yang --- 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 4ed28a6d4186..756af26db207 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" @@ -152,11 +151,9 @@ uint64_t vhost_net_get_acked_features(VHostNetState *n= et) =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 ed9febd378b6..5ef86cd6c384 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; @@ -98,6 +99,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 45c952b1e76d..5b9f08163fc5 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-user.h" #include "chardev/char-fe.h" #include "qapi/error.h" @@ -46,7 +45,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 @@ -241,6 +240,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, .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:49:49 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=1750236179; cv=none; d=zohomail.com; s=zohoarc; b=c26IxyQ/luc3zzvpi9cHZkHJvwcQqoclgwJb+0qe/ZWrdt5RHQ57hoI7DyUhfsDbQ3sTGWztx0C+09l5p70BDB/M1RMAYdMcIu7XkZkuJTJeSu4FlUIoEZf6NsMaaA15KPWTRTvCtZTGaZCE36N2dMihiErsLM1TSFbEH8GxXMw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750236179; 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=R+hj3dZ7vgWAp5yUtgy7frXfJIkxHFfd6Ywsj5GwijU=; b=LQhZHmx2qq0v+eL56e5QaiBdr2V/n0ueoWxnMzjSsSUW5S58LJFAvoeRjL6XS0C85z6ZBOi4xXfQDnveDjvkc99Os5lMSLO6dMavGxTFYMZ8ZOinkz26KYeXhMiGKD0L9aVzi3rqJe2tw1jbO+kPANAr0VEl0G3cYirypMULAxw= 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 1750236178996225.2599438408928; Wed, 18 Jun 2025 01:42:58 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRoMz-0007Lw-OA; Wed, 18 Jun 2025 04:42: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 1uRoMv-0007FH-QA for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:42:06 -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 1uRoMs-000351-4P for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:42:05 -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-160-OTIwHZXsOkmKr8vnROc8Xg-1; Wed, 18 Jun 2025 04:40:11 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 8F74C19560B6; Wed, 18 Jun 2025 08:40:10 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 50BE119560A3; Wed, 18 Jun 2025 08:40:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750236121; 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=R+hj3dZ7vgWAp5yUtgy7frXfJIkxHFfd6Ywsj5GwijU=; b=PSPP43+wY+WgvDlWZ/ZK78TyXMpkrGhf4hK9WmQepxgP7XxmS3h/fCYQ+FZcB/7bPqFKI+ fHyg99cgiCl8glaV1Y28TAkuCCfsbvao4v28HJVMLUmra+Wpu68MEmv9o2Ajg1bwz8YTvG F8p34dAMWWuY0ghaECVYepQsx1T2WBg= X-MC-Unique: OTIwHZXsOkmKr8vnROc8Xg-1 X-Mimecast-MFC-AGG-ID: OTIwHZXsOkmKr8vnROc8Xg_1750236010 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Paolo Bonzini , "Michael S. Tsirkin" , Eric Blake , Stefano Garzarella , Stefan Weil , Jason Wang , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , "Dr. David Alan Gilbert" , Markus Armbruster , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Laurent Vivier Subject: [PATCH 7/8] net: Add passt network backend Date: Wed, 18 Jun 2025 10:39:29 +0200 Message-ID: <20250618083930.451313-8-lvivier@redhat.com> In-Reply-To: <20250618083930.451313-1-lvivier@redhat.com> References: <20250618083930.451313-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 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.89, 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: 1750236180370116600 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 Tested-by: Lei Yang --- 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 | 430 ++++++++++++++++++++++++++++++++++++++++++++++ qapi/net.json | 121 +++++++++++++ qemu-options.hx | 18 ++ 10 files changed, 594 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..c3b89e779c65 --- /dev/null +++ b/net/passt.c @@ -0,0 +1,430 @@ +/* + * 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); + + 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..a027d55f9242 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -112,6 +112,122 @@ 'data': { 'str': 'str' } } =20 +## +# @NetDevPasstOptions: +# +# Unprivileged user-mode network connectivity using passt +# +# @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': { + '*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 +845,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 +875,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 7eb8e02b4b93..f40f30c11d7b 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[,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:49:49 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=1750236165; cv=none; d=zohomail.com; s=zohoarc; b=Cgv0L41o9Baigq8DQpxALFL4ofaYkr+h1GASa4+vVWlbX6B1MVswRa9IH2bTc+Yb0lSWD7utx3TWKsh6RdSm1jYHPYzQaXVjpY216jWOlCh6QyYpR/unsJATJ+Uz9jLrpFLtqPrAAyok475hGmQZOcmpYbOHyJYm2CR5qB/fGHg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1750236165; 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=98fbt4qw4HwYndiyXk5w/3HnYje1W9j4KOXITPX2i1Q=; b=lfJOKd8J2iVDZ63Xg4VNAfkcGGTk04gTyO9L3fvc5Pjj9cascR6G6pNocj6Ub/NeP8N/zrETPDqSFFGV9IYUpaoTfmjBkX9ewE4gMMbHMrlr7lxXElDG5SSvvs2K0vvG+8mog8WOKYI9/jW1azs4DMvXT9/Oz/7+FhIpXiAOOEw= 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 1750236165193337.80710806360514; Wed, 18 Jun 2025 01:42:45 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1uRoN0-0007NQ-HO; Wed, 18 Jun 2025 04:42:11 -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 1uRoMv-0007FE-Ok for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:42:06 -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 1uRoMs-00034x-5a for qemu-devel@nongnu.org; Wed, 18 Jun 2025 04:42:05 -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-340-UZmcFEnYOW6oY0RALYw_Sw-1; Wed, 18 Jun 2025 04:40:16 -0400 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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 AFFE619560A6; Wed, 18 Jun 2025 08:40:15 +0000 (UTC) Received: from lenovo-t14s.redhat.com (unknown [10.44.33.123]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3318A19560B4; Wed, 18 Jun 2025 08:40:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1750236120; 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=98fbt4qw4HwYndiyXk5w/3HnYje1W9j4KOXITPX2i1Q=; b=KlG2+sI5Y8AyKAEnVt2VRSxVXEyLwLWr86f3BQ3eSdNE8rqYfPrwGj9xa93Viht6+JUFRp E0XtmrDqEGl8kcSPAYh+MVDAhvFqomEvN48IXPpUVu08nPDn2wvBCImFV9HDOLUIegFGxJ UREI7USk8DCF4oRNyTLgLLkOZidJ/mY= X-MC-Unique: UZmcFEnYOW6oY0RALYw_Sw-1 X-Mimecast-MFC-AGG-ID: UZmcFEnYOW6oY0RALYw_Sw_1750236015 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Paolo Bonzini , "Michael S. Tsirkin" , Eric Blake , Stefano Garzarella , Stefan Weil , Jason Wang , =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , "Dr. David Alan Gilbert" , Markus Armbruster , =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= , Laurent Vivier Subject: [PATCH 8/8] net/passt: Implement vhost-user backend support Date: Wed, 18 Jun 2025 10:39:30 +0200 Message-ID: <20250618083930.451313-9-lvivier@redhat.com> In-Reply-To: <20250618083930.451313-1-lvivier@redhat.com> References: <20250618083930.451313-1-lvivier@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 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.89, 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: 1750236165896116600 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 Tested-by: Lei Yang --- net/passt.c | 288 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) diff --git a/net/passt.c b/net/passt.c index c3b89e779c65..e4523a5e5617 100644 --- a/net/passt.c +++ b/net/passt.c @@ -7,11 +7,15 @@ */ #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-user.h" #include "stream_data.h" =20 typedef struct NetPasstState { @@ -19,6 +23,15 @@ typedef struct NetPasstState { 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 +40,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 +91,110 @@ static gboolean net_passt_send(QIOChannel *ioc, GIOCon= dition 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, + .get_acked_features =3D passt_get_acked_features, + .save_acked_features =3D passt_save_acked_features, +#endif }; =20 static void net_passt_client_connected(QIOTask *task, gpointer opaque) @@ -163,13 +293,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; + } =20 + /* 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); + + 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