From nobody Sat Apr 11 18:34:30 2026 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=1775590063; cv=none; d=zohomail.com; s=zohoarc; b=dxaljVyoKYxHUolS5aS4MGG5TgoyxiYEYDFKM1rAc/NS095g4eoZ4Yw9aeMggtW4n1ccnwVO6g7PAbWOHKStlQOjmhYirLzGBl35bObFg2lXdAYnqmTtCXf4uHl17jREHekDYE7iMX/73DhbM/oOyWiFiCBgazTbhtZFRloOYHQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775590063; h=Content-Transfer-Encoding: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:Cc; bh=CoeNQxtF/zIAgTe2QQTqxNL1Ip1IeoMjvPuvUUHlKns=; b=ZAcWEWZge1ghKgRGiwD3siVlP5HRkWOd3rtdOhuKofofSmxLYa3wsbI1mQ+ZCpt9Zt6n94x6Rei4vBSN7Y2ra8uI5h0J5WrvcFQ7MB9Pw5eioE57pkHpP+zYLxUYPgoPcur1Tco0rRVP2QxSTmugXeb7i04PIv4WaLstb6KESzY= 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 177559006330464.60558552292105; Tue, 7 Apr 2026 12:27:43 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABXb-0000HJ-7q; Tue, 07 Apr 2026 14:52:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wABUI-0002o3-FB for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:49:22 -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 1w9yfz-0003Gr-1R for qemu-devel@nongnu.org; Tue, 07 Apr 2026 01:08:36 -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-618-gQulgg4ZPfmeiXVBxHMQJA-1; Tue, 07 Apr 2026 01:08:30 -0400 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 E42111800365; Tue, 7 Apr 2026 05:08:29 +0000 (UTC) Received: from S2.redhat.com (unknown [10.72.112.55]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7BCA01800361; Tue, 7 Apr 2026 05:08:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775538514; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=CoeNQxtF/zIAgTe2QQTqxNL1Ip1IeoMjvPuvUUHlKns=; b=QdB7nJlh3TaZPHzx9xfFy6TxMd70GJuIcdVBkiq4xgBHbedJjfCspp1MdCjpx41JW8oslv X3klOUD0LVT8VqK3n/+pbradVb9faN/OxenpE6Cy7CWSWJ79adHpCw24FOh4/q71/uL7iI tpinF/7CDOsnoBUK5W6T9/7+ID5SEZ0= X-MC-Unique: gQulgg4ZPfmeiXVBxHMQJA-1 X-Mimecast-MFC-AGG-ID: gQulgg4ZPfmeiXVBxHMQJA_1775538510 From: Cindy Lu To: lulu@redhat.com, mst@redhat.com, jasowang@redhat.com, zhangckid@gmail.com, lizhijian@fujitsu.com, jmarcin@redhat.com, qemu-devel@nongnu.org Subject: [RFC v4 1/5] net/filter: allow filters on vhost netdevs Date: Tue, 7 Apr 2026 13:05:48 +0800 Message-ID: <20260407050818.2249570-2-lulu@redhat.com> In-Reply-To: <20260407050818.2249570-1-lulu@redhat.com> References: <20260407050818.2249570-1-lulu@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 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=lulu@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-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: qemu development 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: 1775590064117158500 Content-Type: text/plain; charset="utf-8" netfilter_complete() currently rejects netdev backends backed by vhost_net and returns "Vhost is not supported". The AF_PACKET capture/inject chardev work still needs filter objects to sit on top of the existing netdev when the tap queue is owned by vhost, so remove this Signed-off-by: Cindy Lu --- net/filter.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/net/filter.c b/net/filter.c index 76345c1a9d..bb59785911 100644 --- a/net/filter.c +++ b/net/filter.c @@ -13,7 +13,6 @@ =20 #include "net/filter.h" #include "net/net.h" -#include "net/vhost_net.h" #include "qom/object_interfaces.h" #include "qemu/iov.h" #include "qemu/module.h" @@ -254,11 +253,6 @@ static void netfilter_complete(UserCreatable *uc, Erro= r **errp) return; } =20 - if (get_vhost_net(ncs[0])) { - error_setg(errp, "Vhost is not supported"); - return; - } - if (strcmp(nf->position, "head") && strcmp(nf->position, "tail")) { Object *container; Object *obj; --=20 2.52.0 From nobody Sat Apr 11 18:34:30 2026 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=1775590248; cv=none; d=zohomail.com; s=zohoarc; b=OwB1mWfgkPNjwj5WapJdlYDy0uKrGvgx/WWWxGo7k/gJ0KkItV9TAbsZuyAi2iAq1S4I+PI2mdQzk//4vgf6mm9OElhGNCpONGRYr3vhiISF+gDFZGBcYnu/hBiAnXlpd+MhKpPt51YH8N3vpMDyyZfTOQmiyAtLUCcvPOU1pAg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775590248; h=Content-Transfer-Encoding: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:Cc; bh=bSYhPjyMUCbINJQbYKmJPxVIaDBsqWDh+L4xXLOW1QQ=; b=D8RURx+45pCVfr5KuL6oDmmUuccZcB7tQhBZDjCMM8yUveQZgW0QOfTgvrrow+URDvbUB02RjAB22V6hAhGBguvanlg2tWfn7PJzjC0pF8DfDWv1IIJwLio2Dd5aNsEdQlIibBxE7gDwm3KWsUJrUNy77I924ViL1N9iVucmBOI= 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 1775590248600996.9508783226842; Tue, 7 Apr 2026 12:30:48 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABXb-0000HR-MP; Tue, 07 Apr 2026 14:52:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wABUI-0003uc-DO for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:49:22 -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 1w9yg3-0003HK-8N for qemu-devel@nongnu.org; Tue, 07 Apr 2026 01:08:41 -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-522-Xke8I1JmOIud50myCEc5-g-1; Tue, 07 Apr 2026 01:08:35 -0400 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 04146195609F; Tue, 7 Apr 2026 05:08:34 +0000 (UTC) Received: from S2.redhat.com (unknown [10.72.112.55]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 978301800351; Tue, 7 Apr 2026 05:08:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775538518; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=bSYhPjyMUCbINJQbYKmJPxVIaDBsqWDh+L4xXLOW1QQ=; b=D2wyNQjM/4xTm+h2D/OYZnLnTP25I6s/9oasKSK0l8OxQgVQrxJAbqm23Sa+KtM0e3757E og04+ETToayrMCBaxgENEZmI6Uf97uYuZMCHAHoK15h+i/S2XvVMpFyxlAbMLY0O3m/1K0 rHYVTpds7q/VcLWwlkM4W/9Q5XyD84Q= X-MC-Unique: Xke8I1JmOIud50myCEc5-g-1 X-Mimecast-MFC-AGG-ID: Xke8I1JmOIud50myCEc5-g_1775538514 From: Cindy Lu To: lulu@redhat.com, mst@redhat.com, jasowang@redhat.com, zhangckid@gmail.com, lizhijian@fujitsu.com, jmarcin@redhat.com, qemu-devel@nongnu.org Subject: [RFC v4 2/5] chardev/socket: add AF_PACKET initialization Date: Tue, 7 Apr 2026 13:05:49 +0800 Message-ID: <20260407050818.2249570-3-lulu@redhat.com> In-Reply-To: <20260407050818.2249570-1-lulu@redhat.com> References: <20260407050818.2249570-1-lulu@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 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=lulu@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-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: qemu development 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: 1775590250771154100 Content-Type: text/plain; charset="utf-8" Teach socket chardevs to recognize AF_PACKET fds and record the state needed by later TX/RX support. Add af-packet-mode=3Dcapture|inject to QAPI and command-line parsing, reject it for non-fd address types, and validate after a client fd is attached that the supplied fd really is AF_PACKET. The socket chardev now tracks whether the underlying socket is AF_PACKET, owns separate send/receive staging buffers, and resets that state on connection teardown and reconnect. The follow-up TX and RX commits use this setup to translate between the redirector's existing length-prefixed chardev framing and raw L2 packets. Signed-off-by: Cindy Lu --- chardev/char-socket.c | 104 +++++++++++++++++++++++++++++++++- chardev/char.c | 3 + include/chardev/char-socket.h | 13 +++++ qapi/char.json | 23 +++++++- qemu-options.hx | 5 +- 5 files changed, 145 insertions(+), 3 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 62852e3caf..c710fdb497 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -23,6 +23,9 @@ */ =20 #include "qemu/osdep.h" +#ifdef CONFIG_LINUX +#include +#endif #include "chardev/char.h" #include "io/channel-socket.h" #include "io/channel-websock.h" @@ -32,6 +35,7 @@ #include "qapi/error.h" #include "qapi/clone-visitor.h" #include "qapi/qapi-visit-sockets.h" +#include "qapi/util.h" #include "qemu/yank.h" #include "trace.h" =20 @@ -326,6 +330,28 @@ static ssize_t tcp_chr_recv(Chardev *chr, char *buf, s= ize_t len) return ret; } =20 +static bool tcp_chr_is_af_packet(SocketChardev *s) +{ +#ifdef CONFIG_LINUX + return s->sioc && s->sioc->localAddr.ss_family =3D=3D AF_PACKET; +#else + return false; +#endif +} + +static void tcp_chr_reset_af_packet_buf(SocketChardev *s) +{ + s->af_packet_buf_len =3D 0; + s->af_packet_buf_offset =3D 0; +} + +static void tcp_chr_reset_af_packet_send(SocketChardev *s) +{ + s->af_packet_send_len =3D 0; + s->af_packet_send_offset =3D 0; + s->af_packet_send_len_bytes =3D 0; +} + static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond) { SocketChardev *s =3D SOCKET_CHARDEV(chr); @@ -384,6 +410,15 @@ static void tcp_chr_free_connection(Chardev *chr) s->sioc =3D NULL; object_unref(OBJECT(s->ioc)); s->ioc =3D NULL; + g_free(s->af_packet_buf); + s->af_packet_buf =3D NULL; + s->af_packet_buf_size =3D 0; + tcp_chr_reset_af_packet_buf(s); + g_free(s->af_packet_send_buf); + s->af_packet_send_buf =3D NULL; + s->af_packet_send_buf_size =3D 0; + tcp_chr_reset_af_packet_send(s); + s->is_af_packet =3D false; g_free(chr->filename); chr->filename =3D NULL; tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); @@ -889,6 +924,26 @@ static void tcp_chr_set_client_ioc_name(Chardev *chr, =20 } =20 +static bool tcp_chr_validate_af_packet_mode_fd(Chardev *chr, + QIOChannelSocket *sioc, + Error **errp) +{ + SocketChardev *s =3D SOCKET_CHARDEV(chr); + + if (!s->af_packet_mode_set) { + return true; + } + +#ifdef CONFIG_LINUX + if (sioc->localAddr.ss_family =3D=3D AF_PACKET) { + return true; + } +#endif + + error_setg(errp, "'af-packet-mode' requires an AF_PACKET fd"); + return false; +} + static int tcp_chr_new_client(Chardev *chr, QIOChannelSocket *sioc) { SocketChardev *s =3D SOCKET_CHARDEV(chr); @@ -907,6 +962,9 @@ static int tcp_chr_new_client(Chardev *chr, QIOChannelS= ocket *sioc) object_ref(OBJECT(sioc)); s->sioc =3D sioc; object_ref(OBJECT(sioc)); + s->is_af_packet =3D tcp_chr_is_af_packet(s); + tcp_chr_reset_af_packet_buf(s); + tcp_chr_reset_af_packet_send(s); =20 if (s->do_nodelay) { qio_channel_set_delay(s->ioc, false); @@ -951,6 +1009,11 @@ static int tcp_chr_add_client(Chardev *chr, int fd) char_socket_yank_iochannel, QIO_CHANNEL(sioc)); } + if (!tcp_chr_validate_af_packet_mode_fd(chr, sioc, NULL)) { + tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); + object_unref(OBJECT(sioc)); + return -1; + } ret =3D tcp_chr_new_client(chr, sioc); object_unref(OBJECT(sioc)); return ret; @@ -990,7 +1053,17 @@ static int tcp_chr_connect_client_sync(Chardev *chr, = Error **errp) char_socket_yank_iochannel, QIO_CHANNEL(sioc)); } - tcp_chr_new_client(chr, sioc); + if (!tcp_chr_validate_af_packet_mode_fd(chr, sioc, errp)) { + tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); + object_unref(OBJECT(sioc)); + return -1; + } + if (tcp_chr_new_client(chr, sioc) < 0) { + tcp_chr_change_state(s, TCP_CHARDEV_STATE_DISCONNECTED); + object_unref(OBJECT(sioc)); + error_setg(errp, "failed to initialize socket chardev client"); + return -1; + } object_unref(OBJECT(sioc)); return 0; } @@ -1312,6 +1385,11 @@ static bool qmp_chardev_validate_socket(ChardevSocke= t *sock, break; =20 case SOCKET_ADDRESS_TYPE_UNIX: + if (sock->has_af_packet_mode) { + error_setg(errp, + "'af-packet-mode' option requires 'fd' address type= "); + return false; + } if (sock->tls_creds) { error_setg(errp, "'tls_creds' option is incompatible with " @@ -1321,9 +1399,19 @@ static bool qmp_chardev_validate_socket(ChardevSocke= t *sock, break; =20 case SOCKET_ADDRESS_TYPE_INET: + if (sock->has_af_packet_mode) { + error_setg(errp, + "'af-packet-mode' option requires 'fd' address type= "); + return false; + } break; =20 case SOCKET_ADDRESS_TYPE_VSOCK: + if (sock->has_af_packet_mode) { + error_setg(errp, + "'af-packet-mode' option requires 'fd' address type= "); + return false; + } if (sock->tls_creds) { error_setg(errp, "'tls_creds' option is incompatible with " @@ -1386,6 +1474,10 @@ static void qmp_chardev_open_socket(Chardev *chr, s->is_tn3270 =3D is_tn3270; s->is_websock =3D is_websock; s->do_nodelay =3D do_nodelay; + s->af_packet_mode_set =3D sock->has_af_packet_mode; + if (sock->has_af_packet_mode) { + s->af_packet_mode =3D sock->af_packet_mode; + } if (sock->tls_creds) { Object *creds; creds =3D object_resolve_path_component( @@ -1463,6 +1555,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, Cha= rdevBackend *backend, const char *host =3D qemu_opt_get(opts, "host"); const char *port =3D qemu_opt_get(opts, "port"); const char *fd =3D qemu_opt_get(opts, "fd"); + const char *af_packet_mode =3D qemu_opt_get(opts, "af-packet-mode"); #ifdef CONFIG_LINUX bool tight =3D qemu_opt_get_bool(opts, "tight", true); bool abstract =3D qemu_opt_get_bool(opts, "abstract", false); @@ -1516,6 +1609,15 @@ static void qemu_chr_parse_socket(QemuOpts *opts, Ch= ardevBackend *backend, sock->wait =3D qemu_opt_get_bool(opts, "wait", true); sock->has_reconnect_ms =3D qemu_opt_find(opts, "reconnect-ms"); sock->reconnect_ms =3D qemu_opt_get_number(opts, "reconnect-ms", 0); + if (af_packet_mode) { + sock->af_packet_mode =3D + qapi_enum_parse(&ChardevSocketAfPacketMode_lookup, + af_packet_mode, -1, errp); + if (*errp) { + return; + } + sock->has_af_packet_mode =3D true; + } =20 sock->tls_creds =3D g_strdup(qemu_opt_get(opts, "tls-creds")); sock->tls_authz =3D g_strdup(qemu_opt_get(opts, "tls-authz")); diff --git a/chardev/char.c b/chardev/char.c index 3e432195a5..39bb0d5b68 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -910,6 +910,9 @@ QemuOptsList qemu_chardev_opts =3D { },{ .name =3D "websocket", .type =3D QEMU_OPT_BOOL, + },{ + .name =3D "af-packet-mode", + .type =3D QEMU_OPT_STRING, },{ .name =3D "width", .type =3D QEMU_OPT_NUMBER, diff --git a/include/chardev/char-socket.h b/include/chardev/char-socket.h index d6d13ad37f..8af8af6cf8 100644 --- a/include/chardev/char-socket.h +++ b/include/chardev/char-socket.h @@ -63,6 +63,19 @@ struct SocketChardev { int *write_msgfds; size_t write_msgfds_num; bool registered_yank; + bool is_af_packet; + bool af_packet_mode_set; + ChardevSocketAfPacketMode af_packet_mode; + uint8_t *af_packet_buf; + size_t af_packet_buf_size; + size_t af_packet_buf_len; + size_t af_packet_buf_offset; + uint8_t *af_packet_send_buf; + size_t af_packet_send_buf_size; + size_t af_packet_send_len; + size_t af_packet_send_offset; + uint8_t af_packet_send_len_buf[sizeof(uint32_t)]; + size_t af_packet_send_len_bytes; =20 SocketAddress *addr; bool is_listen; diff --git a/qapi/char.json b/qapi/char.json index 140614f82c..61a785727d 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -237,6 +237,22 @@ 'data': { 'device': 'str' }, 'base': 'ChardevCommon' } =20 +## +# @ChardevSocketAfPacketMode: +# +# AF_PACKET fd mode for socket chardevs. +# +# @capture: use recvfrom() to capture raw L2 frames and forward them +# through the existing chardev packet framing +# +# @inject: use sendmsg() to inject framed chardev packets back as raw +# L2 frames +# +# Since: 10.1 +## +{ 'enum': 'ChardevSocketAfPacketMode', + 'data': [ 'capture', 'inject' ] } + ## # @ChardevSocket: # @@ -274,6 +290,10 @@ # Setting this to zero disables this function. # (default: 0) (Since: 9.2) # +# @af-packet-mode: when @addr is an fd that refers to an AF_PACKET +# socket, use raw packet capture or inject instead of stream +# socket I/O (Since: 10.1) +# # Since: 1.4 ## { 'struct': 'ChardevSocket', @@ -286,7 +306,8 @@ '*telnet': 'bool', '*tn3270': 'bool', '*websocket': 'bool', - '*reconnect-ms': 'int' }, + '*reconnect-ms': 'int', + '*af-packet-mode': 'ChardevSocketAfPacketMode' }, 'base': 'ChardevCommon' } =20 ## diff --git a/qemu-options.hx b/qemu-options.hx index fca2b7bc74..0e3ce7f493 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4062,7 +4062,7 @@ The available backends are: A void device. This device will not emit any data, and will drop any data it receives. The null backend does not take any options. =20 -``-chardev socket,id=3Did[,TCP options or unix options][,server=3Don|off][= ,wait=3Don|off][,telnet=3Don|off][,websocket=3Don|off][,reconnect-ms=3Dmill= iseconds][,tls-creds=3Did][,tls-authz=3Did]`` +``-chardev socket,id=3Did[,TCP options or unix options][,server=3Don|off][= ,wait=3Don|off][,telnet=3Don|off][,websocket=3Don|off][,reconnect-ms=3Dmill= iseconds][,tls-creds=3Did][,tls-authz=3Did][,af-packet-mode=3Dcapture|injec= t]`` Create a two-way stream socket, which can be either a TCP or a unix socket. A unix socket will be created if ``path`` is specified. Behaviour is undefined if TCP options are specified for a unix @@ -4095,6 +4095,9 @@ The available backends are: deleted and recreated on the fly while the chardev server is active. If missing, it will default to denying access. =20 + ``af-packet-mode=3Dcapture|inject`` is only valid with ``fd=3D...`` wh= en + the provided file descriptor is an AF_PACKET socket. + TCP and unix socket options are given below: =20 ``TCP options: port=3Dport[,host=3Dhost][,to=3Dto][,ipv4=3Don|off][,ip= v6=3Don|off][,nodelay=3Don|off]`` --=20 2.52.0 From nobody Sat Apr 11 18:34:30 2026 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=1775589808; cv=none; d=zohomail.com; s=zohoarc; b=ecgagUgNpgv3uI4NL2k85sfVTu+cNeYGZwMBE3WnDWXZnDp6a7NDVlYYapqRiFERk0p2W1LaHymGH+HFwro/ct6xfV7mhtLliMgbLmeNe5x8pdRyC+EqWETzl10SNkfKuen2eYS/1+Vus3O+LM3UCHR5Zo7QKpv9hrbTdwX58r4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775589808; h=Content-Transfer-Encoding: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:Cc; bh=MqH93DCOuaDxrfFcJBWlQQkrhR6XKCODDJxRQl2Naqw=; b=IqxnXQnY8EA/+KzjZDuOXn3YRgd8XRLNlk3uRQoVszsRXUGUJfvmd8IOgk35Sak9lN4wCQhoVCTuT0LeL3aL2rUkhY8y9Dg4WU1C8klvnu+IRlCemlIi622NfgCit/0AjYRMGxVQ5P0j2VzQz8d16uiSK2ylC3JRnlNthwQpNWA= 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 1775589808049365.2171454878113; Tue, 7 Apr 2026 12:23:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABXa-0000H0-2j; Tue, 07 Apr 2026 14:52:46 -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 1wABUI-0003JL-C3 for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:49:22 -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 1w9yg6-0003Hr-MB for qemu-devel@nongnu.org; Tue, 07 Apr 2026 01:08:43 -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-38-lbPaI0P7OJyJCrRmcsPWGQ-1; Tue, 07 Apr 2026 01:08:38 -0400 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 DFF4B1800365; Tue, 7 Apr 2026 05:08:37 +0000 (UTC) Received: from S2.redhat.com (unknown [10.72.112.55]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id AD8F91800361; Tue, 7 Apr 2026 05:08:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775538522; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MqH93DCOuaDxrfFcJBWlQQkrhR6XKCODDJxRQl2Naqw=; b=ZWeuc3CM3tIFU4/hfSGgS6aytbiETW/AIMqBidulnhyj+DmkKVCCoKfe4q+ZKgLQnOUtmR VjPgU4pp+648B/BO6qbc2JoGN1XHwklABBwF0RbpZpywDljlWvQqL5yToJkgS+xnE4/NnA ZK45cZf+xNekH3+1SmscJnM16dNB7zE= X-MC-Unique: lbPaI0P7OJyJCrRmcsPWGQ-1 X-Mimecast-MFC-AGG-ID: lbPaI0P7OJyJCrRmcsPWGQ_1775538518 From: Cindy Lu To: lulu@redhat.com, mst@redhat.com, jasowang@redhat.com, zhangckid@gmail.com, lizhijian@fujitsu.com, jmarcin@redhat.com, qemu-devel@nongnu.org Subject: [RFC v4 3/5] io/channel-socket: tolerate AF_PACKET getpeername Date: Tue, 7 Apr 2026 13:05:50 +0800 Message-ID: <20260407050818.2249570-4-lulu@redhat.com> In-Reply-To: <20260407050818.2249570-1-lulu@redhat.com> References: <20260407050818.2249570-1-lulu@redhat.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.4.1 on 10.30.177.111 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=lulu@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-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: qemu development 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: 1775589809047158500 Content-Type: text/plain; charset="utf-8" When -chardev socket,fd=3D... is handed an AF_PACKET socket, getpeername() can fail with EOPNOTSUPP instead of ENOTCONN because packet sockets are not connection-oriented. qio_channel_socket_set_fd() currently treats that as fatal and refuses to wrap the fd, even though getsockname() and the local address are still valid. Treat EOPNOTSUPP the same way as ENOTCONN and leave remoteAddr empty. That keeps existing stream-socket behavior unchanged while allowing AF_PACKET fds to be adopted by QIOChannelSocket. Signed-off-by: Cindy Lu --- io/channel-socket.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/io/channel-socket.c b/io/channel-socket.c index 3053b35ad8..2ed26aefa3 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -115,7 +115,11 @@ qio_channel_socket_set_fd(QIOChannelSocket *sioc, =20 if (getpeername(fd, (struct sockaddr *)&sioc->remoteAddr, &sioc->remoteAddrLen) < 0) { - if (errno =3D=3D ENOTCONN) { + if (errno =3D=3D ENOTCONN +#ifdef EOPNOTSUPP + || errno =3D=3D EOPNOTSUPP +#endif + ) { memset(&sioc->remoteAddr, 0, sizeof(sioc->remoteAddr)); sioc->remoteAddrLen =3D sizeof(sioc->remoteAddr); } else { --=20 2.52.0 From nobody Sat Apr 11 18:34:30 2026 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=1775589304; cv=none; d=zohomail.com; s=zohoarc; b=MjScJNMrBlcIX+3/JDDtgPEFKMmiWI8StQc9405qeFy6H+s9s+3sCrjys/sRuWNq558a0j2LCu6dNhoyIqNiD9V9UzA2awYTXDqxs8wlZdAnuzpBRT01jkxTkZfhehFtZlTHA8Mm2aPV5B8UOjZFVQsxEzkUdXnw1CinELS8JC8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775589304; h=Content-Transfer-Encoding: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:Cc; bh=Gg4529iHncAEaCTY/PX+ysrl8jbN0pCBm9+RUtBBRwc=; b=XKhDEnGSzCu4ORYHhDuZs3rzFHTtRytRRPBwLy/zRpImf6VHjPEehiTapyNnj6jiXyzfSCgdz7TmbSzXSceblVEn9grhx+wATouvewc2N7BmTQHF14OwGlWt9mtI66MnbQXSKpdTEK2Q2H6HfPCS0u6ql53EKgs03OkS+JT598k= 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 1775589304936974.3451967901955; Tue, 7 Apr 2026 12:15:04 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABXY-0000Gh-Vo; Tue, 07 Apr 2026 14:52:45 -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 1wABUI-0003Gt-3J for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:49:22 -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 1w9ygX-0003OZ-UQ for qemu-devel@nongnu.org; Tue, 07 Apr 2026 01:09:11 -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-128-flpCFxObOweQEstrpIocrA-1; Tue, 07 Apr 2026 01:09:04 -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 C374F1956046; Tue, 7 Apr 2026 05:09:03 +0000 (UTC) Received: from S2.redhat.com (unknown [10.72.112.55]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 595E519560A6; Tue, 7 Apr 2026 05:09:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775538548; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Gg4529iHncAEaCTY/PX+ysrl8jbN0pCBm9+RUtBBRwc=; b=i2lgC7UrQgtThApwCXXp6wzUDGPYGkhPc6nkMmPduzhc0/20JvEyEOxzLhn9Wu4yXGIElG PPflyC4WyeXx9M89rDo06ao7bDKZ37nWR0X0w/H0/uCcYqh81ZSv0UPezihkc3Mi9PxDwi mqT6wZneLkfPHsu2X2URRaM7X9T5hH4= X-MC-Unique: flpCFxObOweQEstrpIocrA-1 X-Mimecast-MFC-AGG-ID: flpCFxObOweQEstrpIocrA_1775538543 From: Cindy Lu To: lulu@redhat.com, mst@redhat.com, jasowang@redhat.com, zhangckid@gmail.com, lizhijian@fujitsu.com, jmarcin@redhat.com, qemu-devel@nongnu.org Subject: [RFC v4 4/5] chardev/socket: add AF_PACKET inject path Date: Tue, 7 Apr 2026 13:05:51 +0800 Message-ID: <20260407050818.2249570-5-lulu@redhat.com> In-Reply-To: <20260407050818.2249570-1-lulu@redhat.com> References: <20260407050818.2249570-1-lulu@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=lulu@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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_H2=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-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: qemu development 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: 1775589308268154100 Content-Type: text/plain; charset="utf-8" Add the AF_PACKET inject write path for socket chardevs. When a socket backend is opened with af-packet-mode=3Dinject, tcp_chr_write() no longer sends the redirector stream framing through QIOChannel. Instead it parses the existing 4-byte length header, accumulates one complete packet, and frame on the AF_PACKET fd. Signed-off-by: Cindy Lu --- chardev/char-socket.c | 148 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index c710fdb497..45d06fda8f 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -108,11 +108,159 @@ static void tcp_chr_accept(QIONetListener *listener, static int tcp_chr_read_poll(void *opaque); static void tcp_chr_disconnect_locked(Chardev *chr); =20 +#define TCP_CHARDEV_AF_PACKET_MAX_FRAME_SIZE 65536 + +static bool tcp_chr_uses_af_packet_inject(SocketChardev *s) +{ + return s->is_af_packet && + s->af_packet_mode_set && + s->af_packet_mode =3D=3D CHARDEV_SOCKET_AF_PACKET_MODE_INJECT; +} + +static ssize_t tcp_chr_send_af_packet(SocketChardev *s, + const uint8_t *buf, + size_t len) +{ +#ifdef CONFIG_LINUX + struct iovec iov =3D { + .iov_base =3D (void *)buf, + .iov_len =3D len, + }; + struct msghdr msg =3D { + .msg_iov =3D &iov, + .msg_iovlen =3D 1, + }; + ssize_t ret; + + if (!s->sioc || s->sioc->localAddr.ss_family !=3D AF_PACKET) { + errno =3D ENOTSOCK; + return -1; + } + + do { + ret =3D sendmsg(s->sioc->fd, &msg, 0); + } while (ret < 0 && errno =3D=3D EINTR); + + return ret; +#else + errno =3D EPROTONOSUPPORT; + return -1; +#endif +} + +static bool tcp_chr_af_packet_prepare_send(SocketChardev *s, uint32_t fram= e_len) +{ + if (frame_len > TCP_CHARDEV_AF_PACKET_MAX_FRAME_SIZE) { + errno =3D EMSGSIZE; + return false; + } + + if (frame_len =3D=3D 0) { + s->af_packet_send_len =3D 0; + s->af_packet_send_offset =3D 0; + s->af_packet_send_len_bytes =3D 0; + return true; + } + + if (s->af_packet_send_buf_size < frame_len) { + s->af_packet_send_buf =3D g_realloc(s->af_packet_send_buf, frame_l= en); + s->af_packet_send_buf_size =3D frame_len; + } + + s->af_packet_send_len =3D frame_len; + s->af_packet_send_offset =3D 0; + s->af_packet_send_len_bytes =3D sizeof(s->af_packet_send_len_buf); + return true; +} + +static int tcp_chr_inject_af_packet(Chardev *chr, + SocketChardev *s, + const uint8_t *buf, + int len) +{ + size_t offset =3D 0; + uint32_t frame_len_be; + + while (offset < len) { + size_t copy; + + if (s->af_packet_send_len_bytes < sizeof(s->af_packet_send_len_buf= )) { + copy =3D MIN(sizeof(s->af_packet_send_len_buf) - + s->af_packet_send_len_bytes, + (size_t)len - offset); + memcpy(s->af_packet_send_len_buf + s->af_packet_send_len_bytes, + buf + offset, copy); + s->af_packet_send_len_bytes +=3D copy; + offset +=3D copy; + + if (s->af_packet_send_len_bytes < + sizeof(s->af_packet_send_len_buf)) { + continue; + } + + memcpy(&frame_len_be, s->af_packet_send_len_buf, + sizeof(frame_len_be)); + if (!tcp_chr_af_packet_prepare_send(s, ntohl(frame_len_be))) { + return -1; + } + if (s->af_packet_send_len =3D=3D 0) { + continue; + } + } + + copy =3D MIN(s->af_packet_send_len - s->af_packet_send_offset, + (size_t)len - offset); + memcpy(s->af_packet_send_buf + s->af_packet_send_offset, + buf + offset, copy); + s->af_packet_send_offset +=3D copy; + offset +=3D copy; + + if (s->af_packet_send_offset =3D=3D s->af_packet_send_len) { + ssize_t ret; + + ret =3D tcp_chr_send_af_packet(s, s->af_packet_send_buf, + s->af_packet_send_len); + + if (ret < 0) { + if (errno =3D=3D EAGAIN || errno =3D=3D EWOULDBLOCK) { + return -1; + } + if (tcp_chr_read_poll(chr) <=3D 0) { + trace_chr_socket_poll_err(chr, chr->label); + tcp_chr_disconnect_locked(chr); + } + return -1; + } + + if (ret !=3D (ssize_t)s->af_packet_send_len) { + if (ret >=3D 0) { + errno =3D EIO; + } + if (tcp_chr_read_poll(chr) <=3D 0) { + trace_chr_socket_poll_err(chr, chr->label); + tcp_chr_disconnect_locked(chr); + } + return -1; + } + + s->af_packet_send_len =3D 0; + s->af_packet_send_offset =3D 0; + s->af_packet_send_len_bytes =3D 0; + } + } + + return len; +} + /* Called with chr_write_lock held. */ static int tcp_chr_write(Chardev *chr, const uint8_t *buf, int len) { SocketChardev *s =3D SOCKET_CHARDEV(chr); =20 + if (tcp_chr_uses_af_packet_inject(s)) { + return tcp_chr_inject_af_packet(chr, s, buf, len); + } + if (s->state =3D=3D TCP_CHARDEV_STATE_CONNECTED) { int ret =3D io_channel_send_full(s->ioc, buf, len, s->write_msgfds, --=20 2.52.0 From nobody Sat Apr 11 18:34:30 2026 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=1775589699; cv=none; d=zohomail.com; s=zohoarc; b=jyeDd83cjl0lr5BLica+j064kavJJMV5lfiU1geKMbZadwWZJXm0K6Igo6lzkZe2MQu9Xl+T/DKuXaUsl9T6v9Bx5crC4AfIb80LQBvXVCVC40vYWABqsA/Jp4jTWIGqRXjG+i1TFiI8jLlDBcy7Blmm/gtAC32YEXNymLwGsEE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775589699; h=Content-Transfer-Encoding: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:Cc; bh=Ta00h+hy/b4+1DYEKhFkp7zFZotzTaGXo1VneuiSH34=; b=C3C/KPxOJ7adcjpGff0WMylRLzTN6yav3uEAeurlkVXedN9s8wKKiacePgFnDHcDxyonMVZg7Jk+3JVPIMu3/Oq0BMdqNPZsEPp6m7F2d+Pze75h8ZnFF0GMjjnMMGS869mZyvpWG9QjeZFmDt7xzoHE0NHGEMbBMrvpuFlIkss= 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 1775589699062824.514874758474; Tue, 7 Apr 2026 12:21:39 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wABXa-0000HD-Oi; Tue, 07 Apr 2026 14:52:46 -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 1wABUI-0003wR-3X for qemu-devel@nongnu.org; Tue, 07 Apr 2026 14:49:22 -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 1w9ygb-0003R7-Jt for qemu-devel@nongnu.org; Tue, 07 Apr 2026 01:09:15 -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-381-ad5hLYhuOqWiZ_p9azmfNA-1; Tue, 07 Apr 2026 01:09:09 -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 D3468195608B; Tue, 7 Apr 2026 05:09:07 +0000 (UTC) Received: from S2.redhat.com (unknown [10.72.112.55]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 754451955F2B; Tue, 7 Apr 2026 05:09:04 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1775538552; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Ta00h+hy/b4+1DYEKhFkp7zFZotzTaGXo1VneuiSH34=; b=VPlL8jmFt7VEIhATaSr9d6tj17vho4BLRa9b5czz08EeBQ+VzITg0xvDfQT+vACPDoRLl0 o6xBNckU7rqHzN2WmmOGwu9NZEEtcz+0sSbyLSMXGEXR4fbvQXd5GMJ/G7cgSXyAyzS+i5 oYivYHpOVyZSBc/m5CHP2deNoL+liqg= X-MC-Unique: ad5hLYhuOqWiZ_p9azmfNA-1 X-Mimecast-MFC-AGG-ID: ad5hLYhuOqWiZ_p9azmfNA_1775538548 From: Cindy Lu To: lulu@redhat.com, mst@redhat.com, jasowang@redhat.com, zhangckid@gmail.com, lizhijian@fujitsu.com, jmarcin@redhat.com, qemu-devel@nongnu.org Subject: [RFC v4 5/5] chardev/socket: add AF_PACKET capture path Date: Tue, 7 Apr 2026 13:05:52 +0800 Message-ID: <20260407050818.2249570-6-lulu@redhat.com> In-Reply-To: <20260407050818.2249570-1-lulu@redhat.com> References: <20260407050818.2249570-1-lulu@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=lulu@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -25 X-Spam_score: -2.6 X-Spam_bar: -- X-Spam_report: (-2.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.54, 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_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_PASS=-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: qemu development 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: 1775589700444154100 Content-Type: text/plain; charset="utf-8" Add the AF_PACKET capture read path for socket chardevs. When opened with af-packet-mode=3Dcapture, the read side drains raw frames with recvfrom(), keeps only PACKET_OUTGOING traffic, and feeds the result through the normal chardev frontend interface. Signed-off-by: Cindy Lu --- chardev/char-socket.c | 133 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 2 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 45d06fda8f..76a51a853d 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -107,9 +107,17 @@ static void tcp_chr_accept(QIONetListener *listener, =20 static int tcp_chr_read_poll(void *opaque); static void tcp_chr_disconnect_locked(Chardev *chr); +static void tcp_chr_deliver_af_packet(Chardev *chr); =20 #define TCP_CHARDEV_AF_PACKET_MAX_FRAME_SIZE 65536 =20 +static bool +tcp_chr_uses_af_packet_capture(SocketChardev *s) +{ + return s->is_af_packet && s->af_packet_mode_set && + s->af_packet_mode =3D=3D CHARDEV_SOCKET_AF_PACKET_MODE_CAPTURE; +} + static bool tcp_chr_uses_af_packet_inject(SocketChardev *s) { return s->is_af_packet && @@ -300,6 +308,9 @@ static int tcp_chr_read_poll(void *opaque) return 0; } s->max_size =3D qemu_chr_be_can_write(chr); + if (tcp_chr_uses_af_packet_capture(s) && s->af_packet_buf_len) { + tcp_chr_deliver_af_packet(chr); + } return s->max_size; } =20 @@ -500,6 +511,98 @@ static void tcp_chr_reset_af_packet_send(SocketChardev= *s) s->af_packet_send_len_bytes =3D 0; } =20 +/* Push buffered AF_PACKET capture data into the chardev frontend. */ +static void +tcp_chr_deliver_af_packet(Chardev *chr) +{ + SocketChardev *s =3D SOCKET_CHARDEV(chr); + + while (s->max_size > 0 && s->af_packet_buf_offset < s->af_packet_buf_l= en) { + size_t remaining =3D s->af_packet_buf_len - s->af_packet_buf_offse= t; + size_t chunk =3D MIN((size_t)s->max_size, remaining); + + qemu_chr_be_write(chr, s->af_packet_buf + s->af_packet_buf_offset, + (int)chunk); + s->af_packet_buf_offset +=3D chunk; + s->max_size =3D qemu_chr_be_can_write(chr); + } + + if (s->af_packet_buf_offset =3D=3D s->af_packet_buf_len) { + tcp_chr_reset_af_packet_buf(s); + } +} + +/* Copy buffered AF_PACKET capture data into a synchronous read buffer. */ +static int tcp_chr_copy_af_packet_buf(SocketChardev *s, uint8_t *buf, + int len) { + size_t remaining =3D s->af_packet_buf_len - s->af_packet_buf_offset; + size_t copied =3D MIN((size_t)len, remaining); + + memcpy(buf, s->af_packet_buf + s->af_packet_buf_offset, copied); + s->af_packet_buf_offset +=3D copied; + + if (s->af_packet_buf_offset =3D=3D s->af_packet_buf_len) { + tcp_chr_reset_af_packet_buf(s); + } + + return (int)copied; +} + +static ssize_t +tcp_chr_capture_af_packet(Chardev *chr) +{ +#ifdef CONFIG_LINUX + SocketChardev *s =3D SOCKET_CHARDEV(chr); + struct sockaddr_ll sll; + socklen_t sll_len; + ssize_t size; + uint32_t len; + + if (!tcp_chr_uses_af_packet_capture(s)) { + errno =3D EIO; + return -1; + } + + if (s->af_packet_buf_size < + sizeof(len) + TCP_CHARDEV_AF_PACKET_MAX_FRAME_SIZE) { + s->af_packet_buf =3D + g_realloc(s->af_packet_buf, + sizeof(len) + TCP_CHARDEV_AF_PACKET_MAX_FRAME_SIZE); + s->af_packet_buf_size =3D + sizeof(len) + TCP_CHARDEV_AF_PACKET_MAX_FRAME_SIZE; + } + + for (;;) { + sll_len =3D sizeof(sll); + do { + size =3D recvfrom(s->sioc->fd, s->af_packet_buf + sizeof(len), + TCP_CHARDEV_AF_PACKET_MAX_FRAME_SIZE, 0, + (struct sockaddr *)&sll, &sll_len); + } while (size < 0 && errno =3D=3D EINTR); + + if (size <=3D 0) { + if (size < 0 && errno !=3D EAGAIN && errno !=3D EWOULDBLOCK) { + trace_chr_socket_recv_err(chr, chr->label, g_strerror(errn= o)); + } + return size; + } + + if (sll.sll_pkttype !=3D PACKET_OUTGOING) { + continue; + } + + len =3D htonl(size); + memcpy(s->af_packet_buf, &len, sizeof(len)); + s->af_packet_buf_len =3D sizeof(len) + size; + s->af_packet_buf_offset =3D 0; + return (ssize_t)s->af_packet_buf_len; + } +#else + errno =3D EPROTONOSUPPORT; + return -1; +#endif +} + static GSource *tcp_chr_add_watch(Chardev *chr, GIOCondition cond) { SocketChardev *s =3D SOCKET_CHARDEV(chr); @@ -682,6 +785,22 @@ static gboolean tcp_chr_read(QIOChannel *chan, GIOCond= ition cond, void *opaque) if (len > s->max_size) { len =3D s->max_size; } + if (tcp_chr_uses_af_packet_capture(s)) { + tcp_chr_deliver_af_packet(chr); + if (s->max_size <=3D 0 || s->af_packet_buf_len) { + return TRUE; + } + + size =3D tcp_chr_capture_af_packet(chr); + if (size =3D=3D 0 || (size =3D=3D -1 && errno !=3D EAGAIN)) { + tcp_chr_disconnect(chr); + } else if (size > 0) { + tcp_chr_deliver_af_packet(chr); + } + + return TRUE; + } + size =3D tcp_chr_recv(chr, (void *)buf, len); if (size =3D=3D 0 || (size =3D=3D -1 && errno !=3D EAGAIN)) { /* connection closed */ @@ -715,6 +834,10 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8= _t *buf, int len) int saved_errno; Error *local_err =3D NULL; =20 + if (tcp_chr_uses_af_packet_capture(s) && s->af_packet_buf_len) { + return tcp_chr_copy_af_packet_buf(s, (uint8_t *)buf, len); + } + if (s->state !=3D TCP_CHARDEV_STATE_CONNECTED) { return 0; } @@ -723,7 +846,14 @@ static int tcp_chr_sync_read(Chardev *chr, const uint8= _t *buf, int len) error_report_err(local_err); return -1; } - size =3D tcp_chr_recv(chr, (void *) buf, len); + if (tcp_chr_uses_af_packet_capture(s)) { + size =3D tcp_chr_capture_af_packet(chr); + if (size > 0) { + size =3D tcp_chr_copy_af_packet_buf(s, (uint8_t *)buf, len); + } + } else { + size =3D tcp_chr_recv(chr, (void *)buf, len); + } saved_errno =3D errno; if (s->state !=3D TCP_CHARDEV_STATE_DISCONNECTED) { if (!qio_channel_set_blocking(s->ioc, false, &local_err)) { @@ -1448,7 +1578,6 @@ static gboolean socket_reconnect_timeout(gpointer opa= que) return false; } =20 - static int qmp_chardev_open_socket_server(Chardev *chr, bool is_telnet, bool is_waitconnect, --=20 2.52.0