From patchwork Wed Oct 5 16:20:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999441 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 59512C433F5 for ; Wed, 5 Oct 2022 16:30:45 +0000 (UTC) Received: from localhost ([::1]:44838 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7IC-0006Lr-Cc for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:30:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:50406) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og790-0007GX-D4 for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:14 -0400 Received: from mout.kundenserver.de ([212.227.17.24]:59363) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78u-0002nK-8A for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:12 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MBUuP-1oUF1z2qEB-00Cze1; Wed, 05 Oct 2022 18:20:56 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" , Stefano Brivio Subject: [PATCH v10 01/17] net: introduce convert_host_port() Date: Wed, 5 Oct 2022 18:20:35 +0200 Message-Id: <20221005162051.1120041-2-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:GJ0hD+gVmW1BsbqtfdvsFukChvBdM1Z4/MTJabtitC8IKo5O3uL j+sQ1oPEkD3TEi3TMApsGxqA0aLu+tOEc7bW4zuJmG5x/Exnkgx6y5gbX8kto45+RlPGM2e d4LPBCe1qsZUMX6nSZP1NvSgJZtOnU+KwNQ9fmjTmkhwuBh3wRQm/y5zbFujqbj2wVPZgLt ox7TQ2uFikPS7lmnHghdQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:z+xaJoZr96s=:e3KyDLZB6vc4vjC4vx5gxL cReNAidqoQZ11VnUJ9pa/6+8DYgHIGdcx/9ABm+czgVIilv3XtE1GiOq0oVsmQE5u4zyLXHoz oPofzVFoMNtg4QyIHJFzRhCTshLf6OF9sO0eId85S1nBv/XV5frn//IQ4QkxpP72fM5BzjyxP f7FrOFhWWFH+LGwEGp3DwEe0TT/XyE4ic9FWetf5ymw7hsGIneb4fPfM3XUjItazMJHmMMTUJ QTBxgO+19gLPwW/Epr2mmSv8tzt0BfDj/RCLGNAHz/p50Dx0MFTt0LHjnRm1PWK4U0GmShRoJ zabLd+uRDhZ7YK/gQeb1Quc3Jva1U4GBoJrPLcZplI8CxaXVbTiJleovGLMKQglDcmcoFzNAJ gwvgzgmjArdq97dtw5/pTGgTvB6qoZuS7wkb4CRk5/0AHfME30R2QQCkXM34g4NEwGZf4y5zu itfuepmkjh3RL1QHHNRC0q2zI4kIvsgqVEfhOBVSHvC5uFAjtr4GEpmTj+JKo4uPWmgZvRifg CXjPtXkPQaCirQLAGMswcHFH/5MegMRomrOcKedt8eaIa8ubPkUgHBCLdKatVR7KZkMQuGJCV AiJS6BEKLYztlC1+atMXyhYzsHdV/NBYP+oyqUdAsDzue2meYPQvnfi1q7kIuoPRwdXUFo34a Eoqwe+7BbES4sL+Pv2zihyKyglFQvCnYhkR0SM0S+7RgWHiMIngnfUfWebIDDYk7QpIPtmnFy fAdrQI1jMS6j9DJOgYa6jxcqgNw7YMeIUSTaUGO2d+EVNE06qEH8lJsAB3OAenLgx5Z+KVjOO UHLnkxV Received-SPF: permerror client-ip=212.227.17.24; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Laurent Vivier Reviewed-by: Stefano Brivio Reviewed-by: David Gibson --- include/qemu/sockets.h | 2 ++ net/net.c | 62 ++++++++++++++++++++++-------------------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index 036745e58653..db4bedb6fa20 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -65,6 +65,8 @@ void socket_listen_cleanup(int fd, Error **errp); int socket_dgram(SocketAddress *remote, SocketAddress *local, Error **errp); /* Old, ipv4 only bits. Don't use for new code. */ +int convert_host_port(struct sockaddr_in *saddr, const char *host, + const char *port, Error **errp); int parse_host_port(struct sockaddr_in *saddr, const char *str, Error **errp); int socket_init(void); diff --git a/net/net.c b/net/net.c index 2db160e0634d..d2288bd3a929 100644 --- a/net/net.c +++ b/net/net.c @@ -66,55 +66,57 @@ static QTAILQ_HEAD(, NetClientState) net_clients; /***********************************************************/ /* network device redirectors */ -int parse_host_port(struct sockaddr_in *saddr, const char *str, - Error **errp) +int convert_host_port(struct sockaddr_in *saddr, const char *host, + const char *port, Error **errp) { - gchar **substrings; struct hostent *he; - const char *addr, *p, *r; - int port, ret = 0; + const char *r; + long p; memset(saddr, 0, sizeof(*saddr)); - substrings = g_strsplit(str, ":", 2); - if (!substrings || !substrings[0] || !substrings[1]) { - error_setg(errp, "host address '%s' doesn't contain ':' " - "separating host from port", str); - ret = -1; - goto out; - } - - addr = substrings[0]; - p = substrings[1]; - saddr->sin_family = AF_INET; - if (addr[0] == '\0') { + if (host[0] == '\0') { saddr->sin_addr.s_addr = 0; } else { - if (qemu_isdigit(addr[0])) { - if (!inet_aton(addr, &saddr->sin_addr)) { + if (qemu_isdigit(host[0])) { + if (!inet_aton(host, &saddr->sin_addr)) { error_setg(errp, "host address '%s' is not a valid " - "IPv4 address", addr); - ret = -1; - goto out; + "IPv4 address", host); + return -1; } } else { - he = gethostbyname(addr); + he = gethostbyname(host); if (he == NULL) { - error_setg(errp, "can't resolve host address '%s'", addr); - ret = -1; - goto out; + error_setg(errp, "can't resolve host address '%s'", host); + return -1; } saddr->sin_addr = *(struct in_addr *)he->h_addr; } } - port = strtol(p, (char **)&r, 0); - if (r == p) { - error_setg(errp, "port number '%s' is invalid", p); + if (qemu_strtol(port, &r, 0, &p) != 0) { + error_setg(errp, "port number '%s' is invalid", port); + return -1; + } + saddr->sin_port = htons(p); + return 0; +} + +int parse_host_port(struct sockaddr_in *saddr, const char *str, + Error **errp) +{ + gchar **substrings; + int ret; + + substrings = g_strsplit(str, ":", 2); + if (!substrings || !substrings[0] || !substrings[1]) { + error_setg(errp, "host address '%s' doesn't contain ':' " + "separating host from port", str); ret = -1; goto out; } - saddr->sin_port = htons(port); + + ret = convert_host_port(saddr, substrings[0], substrings[1], errp); out: g_strfreev(substrings); From patchwork Wed Oct 5 16:20:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999440 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6BB68C433F5 for ; Wed, 5 Oct 2022 16:29:01 +0000 (UTC) Received: from localhost ([::1]:33786 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7GW-0005Pj-Ca for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:29:00 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:50402) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78y-0007Ep-4c for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:12 -0400 Received: from mout.kundenserver.de ([212.227.17.24]:57033) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78u-0002nL-4u for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:11 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MTRIg-1oldQL3Fwy-00ThPq; Wed, 05 Oct 2022 18:20:58 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" Subject: [PATCH v10 02/17] net: remove the @errp argument of net_client_inits() Date: Wed, 5 Oct 2022 18:20:36 +0200 Message-Id: <20221005162051.1120041-3-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:OdenA11DsdouddbXZwvud80GTiH/Zx+EhrHZvYrM4QFqqJP/giS bxpKLTonGAkHCUCNo3WbSjtiqxWL0XKNSN139Hz0DbsAN88vl9PBftxndyMrea1HTRUVPk+ J76gMOlyqOzj3Va5d7a20BcKBHg7NxazstzZdTNtY+OH/7nSG3NzdEwXKkiDcWmH1pe4sPM vlzS2WhlsIYaXvQBuUeuQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:sQ66LQuHyCE=:J7GZ9o1dPj4TlFgRjYLkb3 iC3D6krggT82/r6jSghN92Xy0+cb/kI0/+xqR7OestBw2Q/mcCCa3vJXeLZF9ORh4wE9bGNNi aNDtpYX9I5cwEODOUhPL4xPTrms3BmU7uhUq2vmZyTKE7nMxOLufT5vo0/JLw06rGwQM0a381 dMV6RHWzZ6P3d6bMwqO0RSSoE+OShgUmUqAu4e0fD6BR2HHjhBPcyP/viosL95G0vmFHwh0Bx VKMswrjNfE44GmbjjD+Unt4ATV2DS9gvJSR7aoOWALgKS0s1wqUvmoyJFbJJswiGJ2Dm20DXB 4DKixefDJJ3qpEb+VLaWDLZRupEMGyWHNZkeY9QCLiOAdSqOQ4gY1r9Wit/qplwdEcSAsi7b+ nQjP9/KrxMXJAjEtQhmxiTOUQ1KsoSD7L2PXpm5d/rFzpmuJzerRjPVSmgfhjqcfOHc1hmhWe /lslbx12KGE8iZnIgcQzYBVeW5NPNDT54uXXHSILZDacl2527IE6NKqUtAuY7WwQfLQg0wF0p c17TrGeT1hfXD3yPUZfKgXlZ4ZIp2RiqsaHplkCMtrHf2BEfKdcnZFeLBiPA/m8G4UJOu/Dgb 0E1q6J+PEKZWZ1dG2fqO8DCI3WxlsOc7r6AyFMzunK0XDAiWgNS+SMlBIc11AB37XccXOWB74 495bVOFjeOG2SgYUPdB4UF3ap4oA4PzUGNeQfUT5QgARTgSlsGutlybYrZOVn27mM6cn5bZXQ w5LSlPgKWdsNRHuLVZ0/fBRGNBMer3ptu75lBqnTfi93hT2NrWXePQis+x8Kqj6NhvEcIF9+b dIYtyiY Received-SPF: permerror client-ip=212.227.17.24; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The only caller passes &error_fatal, so use this directly in the function. It's what we do for -blockdev, -device, and -object. Suggested-by: Markus Armbruster Signed-off-by: Laurent Vivier Reviewed-by: Markus Armbruster Reviewed-by: David Gibson --- include/net/net.h | 2 +- net/net.c | 20 +++++++------------- softmmu/vl.c | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/include/net/net.h b/include/net/net.h index 81d0b21defce..c1c34a58f849 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -222,7 +222,7 @@ extern const char *host_net_devices[]; /* from net.c */ int net_client_parse(QemuOptsList *opts_list, const char *str); void show_netdevs(void); -int net_init_clients(Error **errp); +void net_init_clients(void); void net_check_clients(void); void net_cleanup(void); void hmp_host_net_add(Monitor *mon, const QDict *qdict); diff --git a/net/net.c b/net/net.c index d2288bd3a929..15958f881776 100644 --- a/net/net.c +++ b/net/net.c @@ -1562,27 +1562,21 @@ out: return ret; } -int net_init_clients(Error **errp) +void net_init_clients(void) { net_change_state_entry = qemu_add_vm_change_state_handler(net_vm_change_state_handler, NULL); QTAILQ_INIT(&net_clients); - if (qemu_opts_foreach(qemu_find_opts("netdev"), - net_init_netdev, NULL, errp)) { - return -1; - } - - if (qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL, errp)) { - return -1; - } + qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, + &error_fatal); - if (qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL, errp)) { - return -1; - } + qemu_opts_foreach(qemu_find_opts("nic"), net_param_nic, NULL, + &error_fatal); - return 0; + qemu_opts_foreach(qemu_find_opts("net"), net_init_client, NULL, + &error_fatal); } int net_client_parse(QemuOptsList *opts_list, const char *optarg) diff --git a/softmmu/vl.c b/softmmu/vl.c index 9abadcc15051..351eab4cd5f1 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1906,7 +1906,7 @@ static void qemu_create_late_backends(void) qtest_server_init(qtest_chrdev, qtest_log, &error_fatal); } - net_init_clients(&error_fatal); + net_init_clients(); object_option_foreach_add(object_create_late); From patchwork Wed Oct 5 16:20:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999477 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BE702C433F5 for ; Wed, 5 Oct 2022 16:42:42 +0000 (UTC) Received: from localhost ([::1]:38704 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7Tl-0001qh-QI for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:42:41 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46928) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og794-0007PK-Af for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:18 -0400 Received: from mout.kundenserver.de ([217.72.192.73]:42961) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78x-0002nf-F2 for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:17 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MOzKk-1oq5Pq3ZWe-00PLqI; Wed, 05 Oct 2022 18:20:59 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" Subject: [PATCH v10 03/17] net: simplify net_client_parse() error management Date: Wed, 5 Oct 2022 18:20:37 +0200 Message-Id: <20221005162051.1120041-4-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:LTn9gCHCzHBSaiI423858RJie+oU0xjnNqPvNFuZ/mBwA+E7W+H XwpPIVxM2IuqPYhJ54rt+lvR3l3+xSx60CQKI3xViQPLHZhH09nIMUk0nJvERwlaPy5wgHv B/LfLPgxam52vpfmdZ2Qclrw0qq/rjt/SGkJZs1gwQ+Al8GoFBYFFq5NIvZ7FFJwsdjJ17u Byy1hNYS3rEyxa8Z5H79g== X-UI-Out-Filterresults: notjunk:1;V03:K0:X97xJnjK6+k=:erRJC7bMOEm5bn9g84KB6K l1d5E6ZFt3ZFAox/lCPZ4IYO8NW3ZO9gxsgkb/J7n7IDivlfEpkiAl5zSqdtxCd7rdmX0wMZ7 XGnMKs693MBGV8MFhQ5oN113O5J+W5j5O9RDTJ4CMXD9OmqJk3Wfc3dhifDarzMYyoH0Oojjq 9s7XnuNtECtqHGPJyn78m2O/bU4o6YHFf6MtqUo5YuBRbG8+/nL2RdZiSZcZALrfwhW8FMrfs WriIqpScdhB41BQcFB1lgQlqE/3tiYqjUYWkEG1CycoyCJ/tTnLf4XMduO3Nt15hwWTaJpDu2 WKvxW0CucJjkrYB7zv02yioRwUdXiJ/+fib4zvZUvKeZxORK1vgGVPvp71/ogYK2k/C5AC2lO Mtlh5dEJnMhCYNm8N4iOU2QxnIi55EynX4iUdPDX+A9RF5HWp667ClOCXGxX6RSnmhIrSGP7e VoA4+4QKh4NmINB08b+1q2ZGjpZCdqwWREC/227yiIUpMajacNVfyBc8cWp+QAzjxMRJrxtLl hYglFGvmFOGGbytKLohomYTQY+/4+qrj2NLSm6TWcN/9rSxc1hGaCGWKgbwl481U/Az+heeDc G2Ekw2db6UB4UI7JYeWHYm+7p2ZhhKxY9kpQ/0rNEzXg4g5wO+1wFGyzUotouSSwQjaNp6r9j /1YQ7Fzx/Qr/TEJNCi60K6Pukx0kTrEgS4x9VHHqVn2loChA20jl5fK4pWOHm8KMTu+LyVXor QKRkWBCPC6bGpVSiL2YWJ9o7SQ7JUk515B9iP8twu94WEUpUSPdkPoyNYQ3lkyJYgaCop1gIe OziwGtL Received-SPF: permerror client-ip=217.72.192.73; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, T_SPF_HELO_TEMPERROR=0.01 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" All net_client_parse() callers exit in case of error. Move exit(1) to net_client_parse() and remove error checking from the callers. Suggested-by: Markus Armbruster Signed-off-by: Laurent Vivier Reviewed-by: Markus Armbruster Reviewed-by: David Gibson --- include/net/net.h | 2 +- net/net.c | 6 ++---- softmmu/vl.c | 12 +++--------- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/include/net/net.h b/include/net/net.h index c1c34a58f849..55023e7e9fa9 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -220,7 +220,7 @@ extern NICInfo nd_table[MAX_NICS]; extern const char *host_net_devices[]; /* from net.c */ -int net_client_parse(QemuOptsList *opts_list, const char *str); +void net_client_parse(QemuOptsList *opts_list, const char *str); void show_netdevs(void); void net_init_clients(void); void net_check_clients(void); diff --git a/net/net.c b/net/net.c index 15958f881776..f056e8aebfb2 100644 --- a/net/net.c +++ b/net/net.c @@ -1579,13 +1579,11 @@ void net_init_clients(void) &error_fatal); } -int net_client_parse(QemuOptsList *opts_list, const char *optarg) +void net_client_parse(QemuOptsList *opts_list, const char *optarg) { if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { - return -1; + exit(1); } - - return 0; } /* From FreeBSD */ diff --git a/softmmu/vl.c b/softmmu/vl.c index 351eab4cd5f1..2bf2d66c6b49 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2809,21 +2809,15 @@ void qemu_init(int argc, char **argv) break; case QEMU_OPTION_netdev: default_net = 0; - if (net_client_parse(qemu_find_opts("netdev"), optarg) == -1) { - exit(1); - } + net_client_parse(qemu_find_opts("netdev"), optarg); break; case QEMU_OPTION_nic: default_net = 0; - if (net_client_parse(qemu_find_opts("nic"), optarg) == -1) { - exit(1); - } + net_client_parse(qemu_find_opts("nic"), optarg); break; case QEMU_OPTION_net: default_net = 0; - if (net_client_parse(qemu_find_opts("net"), optarg) == -1) { - exit(1); - } + net_client_parse(qemu_find_opts("net"), optarg); break; #ifdef CONFIG_LIBISCSI case QEMU_OPTION_iscsi: From patchwork Wed Oct 5 16:20:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999469 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3D98FC433F5 for ; Wed, 5 Oct 2022 16:39:15 +0000 (UTC) Received: from localhost ([::1]:51936 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7QQ-00061z-9Y for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:39:14 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46930) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og794-0007PQ-EN for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:18 -0400 Received: from mout.kundenserver.de ([212.227.17.13]:42549) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78x-0002ns-ED for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:18 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1N3sZy-1pO0Vv3qoC-00zkRm; Wed, 05 Oct 2022 18:21:00 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" Subject: [PATCH v10 04/17] qapi: net: introduce a way to bypass qemu_opts_parse_noisily() Date: Wed, 5 Oct 2022 18:20:38 +0200 Message-Id: <20221005162051.1120041-5-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:AQbIoOXhDDh0aljyn4wjtrGt7UUDOPfYQ63YFqVqnOO2MuYI2JB Lh3IFC0hl/8fz0aVAA36vieRloWDEPIU5Dm0TlHwoZ8xa1Xs5jL32A+MaWm0t0jJ9GkFPqx j51i/0cP2FiRERpRYezWYruHIxUgi6JK7RKT3cHlHWQqng+dwIc5HZ+yxQi6OGPP07epSvs /SLiFtQILnI6y41gl9R5Q== X-UI-Out-Filterresults: notjunk:1;V03:K0:hG7mHo1kMSI=:DqIMstv2RhkxW6sNndDl6v ityaeBI+K6ggEgTAgpIomoPGoGI+pi2iERNskkkUP/S3SPfCf33Enuq+2lXEXhJDZuuUOX3xH LAlUji6rV3+gsUHCp/fYJRbWcRRq+GP570dcnReLLoxYxaehKQ9PbaBJ09s/fKUBzHcjFUdHh HKGcQSFoUhZviulV+ogR7+XvrZCr/Oy+Nccy5lQWg/ZS6s3KVogOrpngpRpaMlOyfifX7Or2F aGqQJsLMduXkbWyENcxY7SsX2rssl83ljkrrWzwLDFSs4dQ7jph8/JW6ZoxY9VdUxUnWNglyA JRdJFZJ0+8ulKUHJI24TIJ8UrhK/eWG0Np6fyl6LEQ3MirqRw4Aa6okositB/DpZ6Gin5legN tYosuunlXf+Hv72vuVxhG6LXSiWlnwUoedtMgLe2FROVhHRxhXH4OiTFFCndj86Of7nSlaOHr s96PTLtHR+Rrf0NlyRcQifOzU9rW5BBnTfwHuSbu+MtEvVTRZUnMQ0sHGw5fniVUHveFOtnSR q/3wMq/Z/Wc10v44wocqKQeD0gv1MDUarHAcAYlde1VXqSbRBFavScMOmtQKYXml6fj+UcbaC TkzRtjDPiKnWymh+sBe9H79Mw07il4ga/mGsrmZQqGVR8NNg0CWBE2GPztEtAeAOGsP3RbQ6C 21FW/afUnri2xzMFGBvA1n6JWALvirRZsbec1DwN5gYqhn3EpiJRSflGiptpEtRnFXbYI75d8 xZMmkWopCsCghULkE6ukWk5S7fF1me3hxYkt30QJffSYNDwzo8AtyUBx9VYfXk6wN/eDKNdzM YmiXmtP Received-SPF: permerror client-ip=212.227.17.13; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, T_SPF_HELO_TEMPERROR=0.01 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" As qemu_opts_parse_noisily() flattens the QAPI structures ("type" field of Netdev structure can collides with "type" field of SocketAddress), we introduce a way to bypass qemu_opts_parse_noisily() and use directly visit_type_Netdev() to parse the backend parameters. More details from Markus: qemu_init() passes the argument of -netdev, -nic, and -net to net_client_parse(). net_client_parse() parses with qemu_opts_parse_noisily(), passing QemuOptsList qemu_netdev_opts for -netdev, qemu_nic_opts for -nic, and qemu_net_opts for -net. Their desc[] are all empty, which means any keys are accepted. The result of the parse (a QemuOpts) is stored in the QemuOptsList. Note that QemuOpts is flat by design. In some places, we layer non-flat on top using dotted keys convention, but not here. net_init_clients() iterates over the stored QemuOpts, and passes them to net_init_netdev(), net_param_nic(), or net_init_client(), respectively. These functions pass the QemuOpts to net_client_init(). They also do other things with the QemuOpts, which we can ignore here. net_client_init() uses the opts visitor to convert the (flat) QemOpts to a (non-flat) QAPI object Netdev. Netdev is also the argument of QMP command netdev_add. The opts visitor was an early attempt to support QAPI in (QemuOpts-based) CLI. It restricts QAPI types to a certain shape; see commit eb7ee2cbeb "qapi: introduce OptsVisitor". A more modern way to support QAPI is qobject_input_visitor_new_str(). It uses keyval_parse() instead of QemuOpts for KEY=VALUE,... syntax, and it also supports JSON syntax. The former isn't quite as expressive as JSON, but it's a lot closer than QemuOpts + opts visitor. This commit paves the way to use of the modern way instead. Signed-off-by: Laurent Vivier Reviewed-by: Markus Armbruster --- include/net/net.h | 2 ++ net/net.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ softmmu/vl.c | 6 ++++- 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/include/net/net.h b/include/net/net.h index 55023e7e9fa9..025dbf1e143b 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -220,6 +220,8 @@ extern NICInfo nd_table[MAX_NICS]; extern const char *host_net_devices[]; /* from net.c */ +bool netdev_is_modern(const char *optarg); +void netdev_parse_modern(const char *optarg); void net_client_parse(QemuOptsList *opts_list, const char *str); void show_netdevs(void); void net_init_clients(void); diff --git a/net/net.c b/net/net.c index f056e8aebfb2..ffe3e5a2cf1d 100644 --- a/net/net.c +++ b/net/net.c @@ -54,6 +54,7 @@ #include "net/colo-compare.h" #include "net/filter.h" #include "qapi/string-output-visitor.h" +#include "qapi/qobject-input-visitor.h" /* Net bridge is currently not supported for W32. */ #if !defined(_WIN32) @@ -63,6 +64,16 @@ static VMChangeStateEntry *net_change_state_entry; static QTAILQ_HEAD(, NetClientState) net_clients; +typedef struct NetdevQueueEntry { + Netdev *nd; + Location loc; + QSIMPLEQ_ENTRY(NetdevQueueEntry) entry; +} NetdevQueueEntry; + +typedef QSIMPLEQ_HEAD(, NetdevQueueEntry) NetdevQueue; + +static NetdevQueue nd_queue = QSIMPLEQ_HEAD_INITIALIZER(nd_queue); + /***********************************************************/ /* network device redirectors */ @@ -1562,6 +1573,20 @@ out: return ret; } +static void netdev_init_modern(void) +{ + while (!QSIMPLEQ_EMPTY(&nd_queue)) { + NetdevQueueEntry *nd = QSIMPLEQ_FIRST(&nd_queue); + + QSIMPLEQ_REMOVE_HEAD(&nd_queue, entry); + loc_push_restore(&nd->loc); + net_client_init1(nd->nd, true, &error_fatal); + loc_pop(&nd->loc); + qapi_free_Netdev(nd->nd); + g_free(nd); + } +} + void net_init_clients(void) { net_change_state_entry = @@ -1569,6 +1594,8 @@ void net_init_clients(void) QTAILQ_INIT(&net_clients); + netdev_init_modern(); + qemu_opts_foreach(qemu_find_opts("netdev"), net_init_netdev, NULL, &error_fatal); @@ -1579,6 +1606,36 @@ void net_init_clients(void) &error_fatal); } +/* + * Does this -netdev argument use modern rather than traditional syntax? + * Modern syntax is to be parsed with netdev_parse_modern(). + * Traditional syntax is to be parsed with net_client_parse(). + */ +bool netdev_is_modern(const char *optarg) +{ + return false; +} + +/* + * netdev_parse_modern() uses modern, more expressive syntax than + * net_client_parse(), but supports only the -netdev option. + * netdev_parse_modern() appends to @nd_queue, whereas net_client_parse() + * appends to @qemu_netdev_opts. + */ +void netdev_parse_modern(const char *optarg) +{ + Visitor *v; + NetdevQueueEntry *nd; + + v = qobject_input_visitor_new_str(optarg, "type", &error_fatal); + nd = g_new(NetdevQueueEntry, 1); + visit_type_Netdev(v, NULL, &nd->nd, &error_fatal); + visit_free(v); + loc_save(&nd->loc); + + QSIMPLEQ_INSERT_TAIL(&nd_queue, nd, entry); +} + void net_client_parse(QemuOptsList *opts_list, const char *optarg) { if (!qemu_opts_parse_noisily(opts_list, optarg, true)) { diff --git a/softmmu/vl.c b/softmmu/vl.c index 2bf2d66c6b49..4a285c26d1d5 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2809,7 +2809,11 @@ void qemu_init(int argc, char **argv) break; case QEMU_OPTION_netdev: default_net = 0; - net_client_parse(qemu_find_opts("netdev"), optarg); + if (netdev_is_modern(optarg)) { + netdev_parse_modern(optarg); + } else { + net_client_parse(qemu_find_opts("netdev"), optarg); + } break; case QEMU_OPTION_nic: default_net = 0; From patchwork Wed Oct 5 16:20:39 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999451 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3A77EC433F5 for ; Wed, 5 Oct 2022 16:32:44 +0000 (UTC) Received: from localhost ([::1]:37074 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7K7-0008HF-Aq for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:32:43 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46924) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og793-0007O1-IV for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:17 -0400 Received: from mout.kundenserver.de ([212.227.17.10]:42553) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78y-0002oJ-Py for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:17 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MFsd7-1oPrJi03Xr-00HPUr; Wed, 05 Oct 2022 18:21:01 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" Subject: [PATCH v10 05/17] net: introduce qemu_set_info_str() function Date: Wed, 5 Oct 2022 18:20:39 +0200 Message-Id: <20221005162051.1120041-6-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:7NOm0Vk5P2uY9HAuTMSwKsy3jn8VrkE7xFhjvP28s5Dc9DdMoaN 41+x2uX74ajZMS+2cCm/JPow2cg59hjN7+NUTeUkA1QSn6cnuI74fOEbjDNADbuLwCS6Dt8 rM+t7CkWbI5JJV7lr1RCg4FsxyWf1ERmvSvYhyfDuHttU/Cox/wZMyPFUxoSd+KJGiOmaCt 1PFopMC3fUhsfzGiFPX8A== X-UI-Out-Filterresults: notjunk:1;V03:K0:bBSKrzLB9tM=:oqAHqhMbgk8lIGxvFtBMYk Vw744TU5GuGRMsQEXIfuM4NtJ1McUNJdOX2KV8aRgJPLUXwZoIH9rqLrUu6/Zl6dXkIcI+CSI Ea83ULI3kMCFFg14fo58zRMOK4eu4BzhhHFcYNL8KCBltEcDzwSfcXc8gBai3dUmleCaOItj3 /AsDiJSzMe4XWsA4fwMCVwaUHfOjIlp1PdhMN1wUobVoCuN7ZC4lrLia7mNHl/+7oKHOveX1P Iwr13n0cQ95K3/E+IA8qcGLZswtTWt8vSlQqNz+gvtA2CZ5pcl+dHloAGMWO7SNf95GzygIiK Sq06RTUF7dhlPm5b0+flDs2Cv5xIvhC48udsozbP9xIRGv1mQeCdHqdQFAsg3hMLxUnsfoU2+ eBDRjJZ9ocWGo+csUD4XvEFYDsAbsdIXB433OaN74fB73xFfT4v8sG6qZUTg5pCDRGSoQ1UWh P0zM36KTBpWOLnLexoqGTb2OOkWBdOldpeYr9s5cDSAfesFsYiFMXuQZBnvLri7O9BMsEE3Ig UZcF2NBwu9z+SP7vnZukdKpTn/JPBD6QPWH/158o0Zn53fZuLgmq4uNoUWJbx3FjbruKcQZnw C9x0DCEkT3CnVcEuky9XKY3dgvYzu5UMEWp66/QaHV1yjcWSKx59r3nd0iGT6ewSGGkpylXsL 5EnTjejzKeZfpuzrMyflDVDOEvkKIiutp6QLFYppBHP1zWFav4FXx/3kWGhRRGrb+h77fzZdP hg16Jt/dkvtKjSDut9wGjBsO1Avbga6CSXkOD5Gkd/ZIBBHAqcn8M4tXkx3FdnmfRRyX5rhlI QWs4D6m Received-SPF: permerror client-ip=212.227.17.10; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Embed the setting of info_str in a function. Signed-off-by: Laurent Vivier Reviewed-by: David Gibson --- include/net/net.h | 1 + net/l2tpv3.c | 3 +-- net/net.c | 17 ++++++++++++----- net/slirp.c | 5 ++--- net/socket.c | 33 ++++++++++++++------------------- net/tap-win32.c | 3 +-- net/tap.c | 13 +++++-------- net/vde.c | 3 +-- net/vhost-user.c | 3 +-- net/vhost-vdpa.c | 2 +- 10 files changed, 39 insertions(+), 44 deletions(-) diff --git a/include/net/net.h b/include/net/net.h index 025dbf1e143b..3db75ff841ff 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -177,6 +177,7 @@ ssize_t qemu_send_packet_async(NetClientState *nc, const uint8_t *buf, void qemu_purge_queued_packets(NetClientState *nc); void qemu_flush_queued_packets(NetClientState *nc); void qemu_flush_or_purge_queued_packets(NetClientState *nc, bool purge); +void qemu_set_info_str(NetClientState *nc, const char *fmt, ...); void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]); bool qemu_has_ufo(NetClientState *nc); bool qemu_has_vnet_hdr(NetClientState *nc); diff --git a/net/l2tpv3.c b/net/l2tpv3.c index af373e5c300c..350041a0d6c0 100644 --- a/net/l2tpv3.c +++ b/net/l2tpv3.c @@ -723,8 +723,7 @@ int net_init_l2tpv3(const Netdev *netdev, l2tpv3_read_poll(s, true); - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "l2tpv3: connected"); + qemu_set_info_str(&s->nc, "l2tpv3: connected"); return 0; outerr: qemu_del_net_client(nc); diff --git a/net/net.c b/net/net.c index ffe3e5a2cf1d..41e05137d431 100644 --- a/net/net.c +++ b/net/net.c @@ -141,13 +141,20 @@ char *qemu_mac_strdup_printf(const uint8_t *macaddr) macaddr[3], macaddr[4], macaddr[5]); } +void qemu_set_info_str(NetClientState *nc, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsnprintf(nc->info_str, sizeof(nc->info_str), fmt, ap); + va_end(ap); +} + void qemu_format_nic_info_str(NetClientState *nc, uint8_t macaddr[6]) { - snprintf(nc->info_str, sizeof(nc->info_str), - "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", - nc->model, - macaddr[0], macaddr[1], macaddr[2], - macaddr[3], macaddr[4], macaddr[5]); + qemu_set_info_str(nc, "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x", + nc->model, macaddr[0], macaddr[1], macaddr[2], + macaddr[3], macaddr[4], macaddr[5]); } static int mac_table[256] = {0}; diff --git a/net/slirp.c b/net/slirp.c index 8679be644420..14a8d592774c 100644 --- a/net/slirp.c +++ b/net/slirp.c @@ -611,9 +611,8 @@ static int net_slirp_init(NetClientState *peer, const char *model, nc = qemu_new_net_client(&net_slirp_info, peer, model, name); - snprintf(nc->info_str, sizeof(nc->info_str), - "net=%s,restrict=%s", inet_ntoa(net), - restricted ? "on" : "off"); + qemu_set_info_str(nc, "net=%s,restrict=%s", inet_ntoa(net), + restricted ? "on" : "off"); s = DO_UPCAST(SlirpState, nc, nc); diff --git a/net/socket.c b/net/socket.c index bfd8596250c4..ade1ecf38b87 100644 --- a/net/socket.c +++ b/net/socket.c @@ -179,7 +179,7 @@ static void net_socket_send(void *opaque) s->fd = -1; net_socket_rs_init(&s->rs, net_socket_rs_finalize, false); s->nc.link_down = true; - memset(s->nc.info_str, 0, sizeof(s->nc.info_str)); + qemu_set_info_str(&s->nc, ""); return; } @@ -387,16 +387,15 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, /* mcast: save bound address as dst */ if (is_connected && mcast != NULL) { s->dgram_dst = saddr; - snprintf(nc->info_str, sizeof(nc->info_str), - "socket: fd=%d (cloned mcast=%s:%d)", - fd, inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + qemu_set_info_str(nc, "socket: fd=%d (cloned mcast=%s:%d)", fd, + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); } else { if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) { s->dgram_dst.sin_family = AF_UNIX; } - snprintf(nc->info_str, sizeof(nc->info_str), - "socket: fd=%d %s", fd, SocketAddressType_str(sa_type)); + qemu_set_info_str(nc, "socket: fd=%d %s", fd, + SocketAddressType_str(sa_type)); } return s; @@ -430,7 +429,7 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer, nc = qemu_new_net_client(&net_socket_info, peer, model, name); - snprintf(nc->info_str, sizeof(nc->info_str), "socket: fd=%d", fd); + qemu_set_info_str(nc, "socket: fd=%d", fd); s = DO_UPCAST(NetSocketState, nc, nc); @@ -497,9 +496,8 @@ static void net_socket_accept(void *opaque) s->fd = fd; s->nc.link_down = false; net_socket_connect(s); - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connection from %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + qemu_set_info_str(&s->nc, "socket: connection from %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); } static int net_socket_listen_init(NetClientState *peer, @@ -597,9 +595,8 @@ static int net_socket_connect_init(NetClientState *peer, return -1; } - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: connect to %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + qemu_set_info_str(&s->nc, "socket: connect to %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; } @@ -642,9 +639,8 @@ static int net_socket_mcast_init(NetClientState *peer, s->dgram_dst = saddr; - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: mcast=%s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + qemu_set_info_str(&s->nc, "socket: mcast=%s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); return 0; } @@ -697,9 +693,8 @@ static int net_socket_udp_init(NetClientState *peer, s->dgram_dst = raddr; - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "socket: udp=%s:%d", - inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port)); + qemu_set_info_str(&s->nc, "socket: udp=%s:%d", inet_ntoa(raddr.sin_addr), + ntohs(raddr.sin_port)); return 0; } diff --git a/net/tap-win32.c b/net/tap-win32.c index 7466f22e77a4..a49c28ba5dc5 100644 --- a/net/tap-win32.c +++ b/net/tap-win32.c @@ -789,8 +789,7 @@ static int tap_win32_init(NetClientState *peer, const char *model, s = DO_UPCAST(TAPState, nc, nc); - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "tap: ifname=%s", ifname); + qemu_set_info_str(&s->nc, "tap: ifname=%s", ifname); s->handle = handle; diff --git a/net/tap.c b/net/tap.c index e203d07a1216..1210a0436de8 100644 --- a/net/tap.c +++ b/net/tap.c @@ -630,8 +630,7 @@ int net_init_bridge(const Netdev *netdev, const char *name, } s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr); - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper, - br); + qemu_set_info_str(&s->nc, "helper=%s,br=%s", helper, br); return 0; } @@ -690,14 +689,12 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer, } if (tap->has_fd || tap->has_fds) { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd); + qemu_set_info_str(&s->nc, "fd=%d", fd); } else if (tap->has_helper) { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s", - tap->helper); + qemu_set_info_str(&s->nc, "helper=%s", tap->helper); } else { - snprintf(s->nc.info_str, sizeof(s->nc.info_str), - "ifname=%s,script=%s,downscript=%s", ifname, script, - downscript); + qemu_set_info_str(&s->nc, "ifname=%s,script=%s,downscript=%s", ifname, + script, downscript); if (strcmp(downscript, "no") != 0) { snprintf(s->down_script, sizeof(s->down_script), "%s", downscript); diff --git a/net/vde.c b/net/vde.c index 1083916bcf52..c0a08662cc30 100644 --- a/net/vde.c +++ b/net/vde.c @@ -98,8 +98,7 @@ static int net_vde_init(NetClientState *peer, const char *model, nc = qemu_new_net_client(&net_vde_info, peer, model, name); - snprintf(nc->info_str, sizeof(nc->info_str), "sock=%s,fd=%d", - sock, vde_datafd(vde)); + qemu_set_info_str(nc, "sock=%s,fd=%d", sock, vde_datafd(vde)); s = DO_UPCAST(VDEState, nc, nc); diff --git a/net/vhost-user.c b/net/vhost-user.c index b1a0247b5981..3a6b90da8661 100644 --- a/net/vhost-user.c +++ b/net/vhost-user.c @@ -341,8 +341,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device, user = g_new0(struct VhostUserState, 1); for (i = 0; i < queues; i++) { nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name); - snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s", - i, chr->label); + qemu_set_info_str(nc, "vhost-user%d to %s", i, chr->label); nc->queue_index = i; if (!nc0) { nc0 = nc; diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 4bc3fd01a878..e1865bea6aa3 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -593,7 +593,7 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, nc = qemu_new_net_control_client(&net_vhost_vdpa_cvq_info, peer, device, name); } - snprintf(nc->info_str, sizeof(nc->info_str), TYPE_VHOST_VDPA); + qemu_set_info_str(nc, TYPE_VHOST_VDPA); s = DO_UPCAST(VhostVDPAState, nc, nc); s->vhost_vdpa.device_fd = vdpa_device_fd; From patchwork Wed Oct 5 16:20:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999468 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id D3DC2C433FE for ; Wed, 5 Oct 2022 16:37:37 +0000 (UTC) Received: from localhost ([::1]:60646 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7Oq-0004Ty-T0 for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:37:36 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:50410) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og791-0007JL-K5 for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:15 -0400 Received: from mout.kundenserver.de ([212.227.17.24]:50283) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78u-0002nM-6h for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:15 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1N3sZy-1pO0Vy1Lhg-00zkRm; Wed, 05 Oct 2022 18:21:03 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" , Stefano Brivio Subject: [PATCH v10 06/17] qapi: net: add stream and dgram netdevs Date: Wed, 5 Oct 2022 18:20:40 +0200 Message-Id: <20221005162051.1120041-7-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:+4xReSbFv+EfAij4R8vsol5052c+3HIAix0xxkkVrVi5sRFgb5+ pBbmPJBuJ9+JlXaIu8hASVQYcLo4zuGXEDImduohh4gxNUYaPBcM/LomZ8dSBCZau47iOJf VGxzT4tLDl6eQ34o8AxFAFcy4R4P1mmZIB5i2QpTUKWQaUJwyRFNMi/NKoLDBeaHnHxcWaV FrnUx+U9cP+Hki40GqVwA== X-UI-Out-Filterresults: notjunk:1;V03:K0:lZl9RRq3fgI=:AVVu+XfKEQN+9U8KvciMUY +7SCy9fMhrg1F483J4OHjXG5qj+8RPiVSZIq/KcdYh92a35W2cH8gg7U7aiNbqXzpf3YCpsvQ UZfCpp0J3JnJEy+3Y2ZkuiEgEQGJyTutqnXpJUmt4dBvCI5Qi/xv/zRGSD69GmZQF6V67PI0F rKd/OlL0YPvfQZo6UyIS1lGXBkGqcLQfEL22JLRvBZ8YboPgvRF9i9P8SxbMhXidSd2xDVWeq hlrOyXhWdPsE53Ar04BCzs5BlINLgHZhYCthVLhhlJ3c7SuGktByQ8JaU45Iw012ukjod6z0+ w7Z+yudn9JltK+0o3+ihReoIleohd+xh3cBh692bgTdd10hqmqHoFl7y5FThNQ6+jcWwGspeb BLKAtDrpgkntmRQEZEHMFTz9h+mrciBXg8vlYHvBjn5Q64UFkOiNJNzW/126KAqt1Zdqfg46w 81KxQYVmqjdXtCyuiumz7ybzqBoyBzj9yRZN+ucPt1E7ZemtdLxAkUqnjZ0SZp5/3gK1Piq3w rCl/tuU2MzTij3SlIGDKgcXhxVbWkvjDfpY+6yUKl/b0d9X79TjXoAGEl0Gp5ekCFA/o3qA0p wWmXcMD2vANFCDdrjJucI3oxSyuea2qooma74HPn7oQZZm9n5KZ5WMINMHak9Z8fM3M6sNX24 eL5BLMf24SZqq5en9qJVhSFsoAJ5HrVgkhX1qlxp/n7BXm4wdDOM6EqBzTbD0jnYlD6aShj38 scBswlCyJvCZGKPLQn0LyY9GBMQMcWQUQLj00sU+Un4WsiHe9168BNbawBkiBKQdh8cqHm82U ICU4g80 Received-SPF: permerror client-ip=212.227.17.24; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Copied from socket netdev file and modified to use SocketAddress to be able to introduce new features like unix socket. "udp" and "mcast" are squashed into dgram netdev, multicast is detected according to the IP address type. "listen" and "connect" modes are managed by stream netdev. An optional parameter "server" defines the mode (server by default) The two new types need to be parsed the modern way with -netdev, because with the traditional way, the "type" field of netdev structure collides with the "type" field of SocketAddress and prevents the correct evaluation of the command line option. Moreover the traditional way doesn't allow to use the same type (SocketAddress) several times with the -netdev option (needed to specify "local" and "remote" addresses). The previous commit paved the way for parsing the modern way, but omitted one detail: how to pick modern vs. traditional, in netdev_is_modern(). We want to pick based on the value of parameter "type". But how to extract it from the option argument? Parsing the option argument, either the modern or the traditional way, extracts it for us, but only if parsing succeeds. If parsing fails, there is no good option. No matter which parser we pick, it'll be the wrong one for some arguments, and the error reporting will be confusing. Fortunately, the traditional parser accepts *anything* when called in a certain way. This maximizes our chance to extract the value of "type", and in turn minimizes the risk of confusing error reporting. Signed-off-by: Laurent Vivier Reviewed-by: Stefano Brivio Acked-by: Markus Armbruster --- hmp-commands.hx | 2 +- net/clients.h | 6 + net/dgram.c | 537 ++++++++++++++++++++++++++++++++++++++++++++++++ net/hub.c | 2 + net/meson.build | 2 + net/net.c | 30 ++- net/stream.c | 425 ++++++++++++++++++++++++++++++++++++++ qapi/net.json | 62 +++++- qemu-options.hx | 12 ++ 9 files changed, 1074 insertions(+), 4 deletions(-) create mode 100644 net/dgram.c create mode 100644 net/stream.c diff --git a/hmp-commands.hx b/hmp-commands.hx index 8ab8000acd9e..da40a7eb04ed 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1276,7 +1276,7 @@ ERST { .name = "netdev_add", .args_type = "netdev:O", - .params = "[user|tap|socket|vde|bridge|hubport|netmap|vhost-user" + .params = "[user|tap|socket|stream|dgram|vde|bridge|hubport|netmap|vhost-user" #ifdef CONFIG_VMNET "|vmnet-host|vmnet-shared|vmnet-bridged" #endif diff --git a/net/clients.h b/net/clients.h index c9157789f2ce..ed8bdfff1e7c 100644 --- a/net/clients.h +++ b/net/clients.h @@ -40,6 +40,12 @@ int net_init_hubport(const Netdev *netdev, const char *name, int net_init_socket(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); +int net_init_stream(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); + +int net_init_dgram(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp); + int net_init_tap(const Netdev *netdev, const char *name, NetClientState *peer, Error **errp); diff --git a/net/dgram.c b/net/dgram.c new file mode 100644 index 000000000000..5339585b8202 --- /dev/null +++ b/net/dgram.c @@ -0,0 +1,537 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2022 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" + +#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" + +typedef struct NetDgramState { + NetClientState nc; + int fd; + SocketReadState rs; + struct sockaddr_in dgram_dst; /* contains destination iff connectionless */ + bool read_poll; /* waiting to receive data? */ + bool write_poll; /* waiting to transmit data? */ +} NetDgramState; + +static void net_dgram_send(void *opaque); +static void net_dgram_writable(void *opaque); + +static void net_dgram_update_fd_handler(NetDgramState *s) +{ + qemu_set_fd_handler(s->fd, + s->read_poll ? net_dgram_send : NULL, + s->write_poll ? net_dgram_writable : NULL, + s); +} + +static void net_dgram_read_poll(NetDgramState *s, bool enable) +{ + s->read_poll = enable; + net_dgram_update_fd_handler(s); +} + +static void net_dgram_write_poll(NetDgramState *s, bool enable) +{ + s->write_poll = enable; + net_dgram_update_fd_handler(s); +} + +static void net_dgram_writable(void *opaque) +{ + NetDgramState *s = opaque; + + net_dgram_write_poll(s, false); + + qemu_flush_queued_packets(&s->nc); +} + +static ssize_t net_dgram_receive(NetClientState *nc, + const uint8_t *buf, size_t size) +{ + NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc); + ssize_t ret; + + do { + if (s->dgram_dst.sin_family != AF_UNIX) { + ret = sendto(s->fd, buf, size, 0, + (struct sockaddr *)&s->dgram_dst, + sizeof(s->dgram_dst)); + } else { + ret = send(s->fd, buf, size, 0); + } + } while (ret == -1 && errno == EINTR); + + if (ret == -1 && errno == EAGAIN) { + net_dgram_write_poll(s, true); + return 0; + } + return ret; +} + +static void net_dgram_send_completed(NetClientState *nc, ssize_t len) +{ + NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc); + + if (!s->read_poll) { + net_dgram_read_poll(s, true); + } +} + +static void net_dgram_rs_finalize(SocketReadState *rs) +{ + NetDgramState *s = container_of(rs, NetDgramState, rs); + + if (qemu_send_packet_async(&s->nc, rs->buf, + rs->packet_len, + net_dgram_send_completed) == 0) { + net_dgram_read_poll(s, false); + } +} + +static void net_dgram_send(void *opaque) +{ + NetDgramState *s = opaque; + int size; + + size = recv(s->fd, s->rs.buf, sizeof(s->rs.buf), 0); + if (size < 0) { + return; + } + if (size == 0) { + /* end of connection */ + net_dgram_read_poll(s, false); + net_dgram_write_poll(s, false); + return; + } + if (qemu_send_packet_async(&s->nc, s->rs.buf, size, + net_dgram_send_completed) == 0) { + net_dgram_read_poll(s, false); + } +} + +static int net_dgram_mcast_create(struct sockaddr_in *mcastaddr, + struct in_addr *localaddr, + Error **errp) +{ + struct ip_mreq imr; + int fd; + int val, ret; +#ifdef __OpenBSD__ + unsigned char loop; +#else + int loop; +#endif + + if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) { + error_setg(errp, "specified mcastaddr %s (0x%08x) " + "does not contain a multicast address", + inet_ntoa(mcastaddr->sin_addr), + (int)ntohl(mcastaddr->sin_addr.s_addr)); + return -1; + } + + fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create datagram socket"); + return -1; + } + + /* + * Allow multiple sockets to bind the same multicast ip and port by setting + * SO_REUSEADDR. This is the only situation where SO_REUSEADDR should be set + * on windows. Use socket_set_fast_reuse otherwise as it sets SO_REUSEADDR + * only on posix systems. + */ + val = 1; + ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't set socket option SO_REUSEADDR"); + goto fail; + } + + ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't bind ip=%s to socket", + inet_ntoa(mcastaddr->sin_addr)); + goto fail; + } + + /* Add host to multicast group */ + imr.imr_multiaddr = mcastaddr->sin_addr; + if (localaddr) { + imr.imr_interface = *localaddr; + } else { + imr.imr_interface.s_addr = htonl(INADDR_ANY); + } + + ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &imr, sizeof(struct ip_mreq)); + if (ret < 0) { + error_setg_errno(errp, errno, + "can't add socket to multicast group %s", + inet_ntoa(imr.imr_multiaddr)); + goto fail; + } + + /* Force mcast msgs to loopback (eg. several QEMUs in same host */ + loop = 1; + ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, + &loop, sizeof(loop)); + if (ret < 0) { + error_setg_errno(errp, errno, + "can't force multicast message to loopback"); + goto fail; + } + + /* If a bind address is given, only send packets from that address */ + if (localaddr != NULL) { + ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, + localaddr, sizeof(*localaddr)); + if (ret < 0) { + error_setg_errno(errp, errno, + "can't set the default network send interface"); + goto fail; + } + } + + qemu_socket_set_nonblock(fd); + return fd; +fail: + if (fd >= 0) { + closesocket(fd); + } + return -1; +} + +static void net_dgram_cleanup(NetClientState *nc) +{ + NetDgramState *s = DO_UPCAST(NetDgramState, nc, nc); + if (s->fd != -1) { + net_dgram_read_poll(s, false); + net_dgram_write_poll(s, false); + close(s->fd); + s->fd = -1; + } +} + +static NetClientInfo net_dgram_socket_info = { + .type = NET_CLIENT_DRIVER_DGRAM, + .size = sizeof(NetDgramState), + .receive = net_dgram_receive, + .cleanup = net_dgram_cleanup, +}; + +static NetDgramState *net_dgram_fd_init(NetClientState *peer, + const char *model, + const char *name, + int fd, int is_fd, + SocketAddress *mcast, + Error **errp) +{ + struct sockaddr_in saddr; + int newfd; + NetClientState *nc; + NetDgramState *s; + SocketAddress *sa; + SocketAddressType sa_type; + + sa = socket_local_address(fd, errp); + if (!sa) { + return NULL; + } + sa_type = sa->type; + qapi_free_SocketAddress(sa); + + /* + * fd passed: multicast: "learn" dgram_dst address from bound address and + * save it. Because this may be "shared" socket from a "master" process, + * datagrams would be recv() by ONLY ONE process: we must "clone" this + * dgram socket --jjo + */ + + if (is_fd && mcast != NULL) { + if (convert_host_port(&saddr, mcast->u.inet.host, + mcast->u.inet.port, errp) < 0) { + goto err; + } + /* must be bound */ + if (saddr.sin_addr.s_addr == 0) { + error_setg(errp, "can't setup multicast destination address"); + goto err; + } + /* clone dgram socket */ + newfd = net_dgram_mcast_create(&saddr, NULL, errp); + if (newfd < 0) { + goto err; + } + /* clone newfd to fd, close newfd */ + dup2(newfd, fd); + close(newfd); + + } + + nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name); + + s = DO_UPCAST(NetDgramState, nc, nc); + + s->fd = fd; + net_socket_rs_init(&s->rs, net_dgram_rs_finalize, false); + net_dgram_read_poll(s, true); + + /* mcast: save bound address as dst */ + if (is_fd && mcast != NULL) { + s->dgram_dst = saddr; + qemu_set_info_str(nc, "fd=%d (cloned mcast=%s:%d)", fd, + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + } else { + if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) { + s->dgram_dst.sin_family = AF_UNIX; + } + + qemu_set_info_str(nc, "fd=%d %s", fd, SocketAddressType_str(sa_type)); + } + + return s; + +err: + closesocket(fd); + return NULL; +} + +static int net_dgram_mcast_init(NetClientState *peer, + const char *model, + const char *name, + SocketAddress *remote, + SocketAddress *local, + Error **errp) +{ + NetDgramState *s; + int fd, ret; + struct sockaddr_in saddr; + + if (remote->type != SOCKET_ADDRESS_TYPE_INET) { + error_setg(errp, "multicast only support inet type"); + return -1; + } + + if (convert_host_port(&saddr, remote->u.inet.host, remote->u.inet.port, + errp) < 0) { + return -1; + } + + if (!local) { + fd = net_dgram_mcast_create(&saddr, NULL, errp); + if (fd < 0) { + return -1; + } + } else { + switch (local->type) { + case SOCKET_ADDRESS_TYPE_INET: { + struct in_addr localaddr; + + if (inet_aton(local->u.inet.host, &localaddr) == 0) { + error_setg(errp, "localaddr '%s' is not a valid IPv4 address", + local->u.inet.host); + return -1; + } + + fd = net_dgram_mcast_create(&saddr, &localaddr, errp); + if (fd < 0) { + return -1; + } + break; + } + case SOCKET_ADDRESS_TYPE_FD: + fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp); + if (fd == -1) { + return -1; + } + ret = qemu_socket_try_set_nonblock(fd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + return -1; + } + break; + default: + error_setg(errp, "only support inet or fd type for local"); + return -1; + } + } + + s = net_dgram_fd_init(peer, model, name, fd, + local->type == SOCKET_ADDRESS_TYPE_FD, + remote, errp); + if (!s) { + return -1; + } + + s->dgram_dst = saddr; + + qemu_set_info_str(&s->nc, "mcast=%s:%d", inet_ntoa(saddr.sin_addr), + ntohs(saddr.sin_port)); + return 0; + +} + + +int net_init_dgram(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + NetDgramState *s; + int fd, ret; + struct sockaddr_in raddr_in; + struct sockaddr_in laddr_in; + SocketAddress *remote, *local; + + assert(netdev->type == NET_CLIENT_DRIVER_DGRAM); + + remote = netdev->u.dgram.remote; + local = netdev->u.dgram.local; + + /* detect multicast address */ + if (remote && remote->type == SOCKET_ADDRESS_TYPE_INET) { + struct sockaddr_in mcastaddr; + + if (convert_host_port(&mcastaddr, remote->u.inet.host, + remote->u.inet.port, errp) < 0) { + return -1; + } + + if (IN_MULTICAST(ntohl(mcastaddr.sin_addr.s_addr))) { + return net_dgram_mcast_init(peer, "dram", name, remote, local, + errp); + } + } + + /* unicast address */ + if (!local) { + error_setg(errp, "dgram requires local= parameter"); + return -1; + } + + if (remote) { + if (local->type == SOCKET_ADDRESS_TYPE_FD) { + error_setg(errp, "don't set remote with local.fd"); + return -1; + } + if (remote->type != local->type) { + error_setg(errp, "remote and local types must be the same"); + return -1; + } + } else { + if (local->type != SOCKET_ADDRESS_TYPE_FD) { + error_setg(errp, "type=inet requires remote parameter"); + return -1; + } + } + + switch (local->type) { + case SOCKET_ADDRESS_TYPE_INET: + if (convert_host_port(&laddr_in, local->u.inet.host, local->u.inet.port, + errp) < 0) { + return -1; + } + + if (convert_host_port(&raddr_in, remote->u.inet.host, + remote->u.inet.port, errp) < 0) { + return -1; + } + + fd = qemu_socket(PF_INET, SOCK_DGRAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create datagram socket"); + return -1; + } + + ret = socket_set_fast_reuse(fd); + if (ret < 0) { + error_setg_errno(errp, errno, + "can't set socket option SO_REUSEADDR"); + closesocket(fd); + return -1; + } + ret = bind(fd, (struct sockaddr *)&laddr_in, sizeof(laddr_in)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't bind ip=%s to socket", + inet_ntoa(laddr_in.sin_addr)); + closesocket(fd); + return -1; + } + qemu_socket_set_nonblock(fd); + break; + case SOCKET_ADDRESS_TYPE_FD: + fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp); + if (fd == -1) { + return -1; + } + ret = qemu_socket_try_set_nonblock(fd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + return -1; + } + break; + default: + error_setg(errp, "only support inet or fd type for local"); + return -1; + } + + s = net_dgram_fd_init(peer, "dgram", name, fd, 0, NULL, errp); + if (!s) { + return -1; + } + + if (remote) { + s->dgram_dst = raddr_in; + } + + switch (local->type) { + case SOCKET_ADDRESS_TYPE_INET: + qemu_set_info_str(&s->nc, "udp=%s:%d/%s:%d", + inet_ntoa(laddr_in.sin_addr), + ntohs(laddr_in.sin_port), + inet_ntoa(raddr_in.sin_addr), + ntohs(raddr_in.sin_port)); + break; + case SOCKET_ADDRESS_TYPE_FD: + qemu_set_info_str(&s->nc, "fd=%d", fd); + break; + default: + g_assert_not_reached(); + } + + return 0; +} diff --git a/net/hub.c b/net/hub.c index 1375738bf121..67ca53485638 100644 --- a/net/hub.c +++ b/net/hub.c @@ -313,6 +313,8 @@ void net_hub_check_clients(void) case NET_CLIENT_DRIVER_USER: case NET_CLIENT_DRIVER_TAP: case NET_CLIENT_DRIVER_SOCKET: + case NET_CLIENT_DRIVER_STREAM: + case NET_CLIENT_DRIVER_DGRAM: case NET_CLIENT_DRIVER_VDE: case NET_CLIENT_DRIVER_VHOST_USER: has_host_dev = 1; diff --git a/net/meson.build b/net/meson.build index d1be76daf361..6cd1e3dab3a6 100644 --- a/net/meson.build +++ b/net/meson.build @@ -13,6 +13,8 @@ softmmu_ss.add(files( 'net.c', 'queue.c', 'socket.c', + 'stream.c', + 'dgram.c', 'util.c', )) diff --git a/net/net.c b/net/net.c index 41e05137d431..dd063d71b7b3 100644 --- a/net/net.c +++ b/net/net.c @@ -48,6 +48,7 @@ #include "qemu/qemu-print.h" #include "qemu/main-loop.h" #include "qemu/option.h" +#include "qemu/keyval.h" #include "qapi/error.h" #include "qapi/opts-visitor.h" #include "sysemu/runstate.h" @@ -1021,6 +1022,8 @@ static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])( #endif [NET_CLIENT_DRIVER_TAP] = net_init_tap, [NET_CLIENT_DRIVER_SOCKET] = net_init_socket, + [NET_CLIENT_DRIVER_STREAM] = net_init_stream, + [NET_CLIENT_DRIVER_DGRAM] = net_init_dgram, #ifdef CONFIG_VDE [NET_CLIENT_DRIVER_VDE] = net_init_vde, #endif @@ -1108,6 +1111,8 @@ void show_netdevs(void) int idx; const char *available_netdevs[] = { "socket", + "stream", + "dgram", "hubport", "tap", #ifdef CONFIG_SLIRP @@ -1620,7 +1625,30 @@ void net_init_clients(void) */ bool netdev_is_modern(const char *optarg) { - return false; + QemuOpts *opts; + bool is_modern; + const char *type; + static QemuOptsList dummy_opts = { + .name = "netdev", + .implied_opt_name = "type", + .head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head), + .desc = { { } }, + }; + + if (optarg[0] == '{') { + /* This is JSON, which means it's modern syntax */ + return true; + } + + opts = qemu_opts_create(&dummy_opts, NULL, false, &error_abort); + qemu_opts_do_parse(opts, optarg, dummy_opts.implied_opt_name, + &error_abort); + type = qemu_opt_get(opts, "type"); + is_modern = !g_strcmp0(type, "stream") || !g_strcmp0(type, "dgram"); + + qemu_opts_reset(&dummy_opts); + + return is_modern; } /* diff --git a/net/stream.c b/net/stream.c new file mode 100644 index 000000000000..37965eb74e1a --- /dev/null +++ b/net/stream.c @@ -0,0 +1,425 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2022 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" + +#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" + +typedef struct NetStreamState { + NetClientState nc; + int listen_fd; + int fd; + SocketReadState rs; + unsigned int send_index; /* number of bytes sent*/ + bool read_poll; /* waiting to receive data? */ + bool write_poll; /* waiting to transmit data? */ +} NetStreamState; + +static void net_stream_send(void *opaque); +static void net_stream_accept(void *opaque); +static void net_stream_writable(void *opaque); + +static void net_stream_update_fd_handler(NetStreamState *s) +{ + qemu_set_fd_handler(s->fd, + s->read_poll ? net_stream_send : NULL, + s->write_poll ? net_stream_writable : NULL, + s); +} + +static void net_stream_read_poll(NetStreamState *s, bool enable) +{ + s->read_poll = enable; + net_stream_update_fd_handler(s); +} + +static void net_stream_write_poll(NetStreamState *s, bool enable) +{ + s->write_poll = enable; + net_stream_update_fd_handler(s); +} + +static void net_stream_writable(void *opaque) +{ + NetStreamState *s = opaque; + + net_stream_write_poll(s, false); + + qemu_flush_queued_packets(&s->nc); +} + +static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf, + size_t size) +{ + NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc); + uint32_t len = htonl(size); + struct iovec iov[] = { + { + .iov_base = &len, + .iov_len = sizeof(len), + }, { + .iov_base = (void *)buf, + .iov_len = size, + }, + }; + size_t remaining; + ssize_t ret; + + remaining = iov_size(iov, 2) - s->send_index; + ret = iov_send(s->fd, iov, 2, s->send_index, remaining); + + if (ret == -1 && errno == EAGAIN) { + ret = 0; /* handled further down */ + } + if (ret == -1) { + s->send_index = 0; + return -errno; + } + if (ret < (ssize_t)remaining) { + s->send_index += ret; + net_stream_write_poll(s, true); + return 0; + } + s->send_index = 0; + return size; +} + +static void net_stream_send_completed(NetClientState *nc, ssize_t len) +{ + NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc); + + if (!s->read_poll) { + net_stream_read_poll(s, true); + } +} + +static void net_stream_rs_finalize(SocketReadState *rs) +{ + NetStreamState *s = container_of(rs, NetStreamState, rs); + + if (qemu_send_packet_async(&s->nc, rs->buf, + rs->packet_len, + net_stream_send_completed) == 0) { + net_stream_read_poll(s, false); + } +} + +static void net_stream_send(void *opaque) +{ + NetStreamState *s = opaque; + int size; + int ret; + uint8_t buf1[NET_BUFSIZE]; + const uint8_t *buf; + + size = recv(s->fd, buf1, sizeof(buf1), 0); + if (size < 0) { + if (errno != EWOULDBLOCK) { + goto eoc; + } + } else if (size == 0) { + /* end of connection */ + eoc: + net_stream_read_poll(s, false); + net_stream_write_poll(s, false); + if (s->listen_fd != -1) { + qemu_set_fd_handler(s->listen_fd, net_stream_accept, NULL, s); + } + closesocket(s->fd); + + s->fd = -1; + net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); + s->nc.link_down = true; + qemu_set_info_str(&s->nc, ""); + + return; + } + buf = buf1; + + ret = net_fill_rstate(&s->rs, buf, size); + + if (ret == -1) { + goto eoc; + } +} + +static void net_stream_cleanup(NetClientState *nc) +{ + NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc); + if (s->fd != -1) { + net_stream_read_poll(s, false); + net_stream_write_poll(s, false); + close(s->fd); + s->fd = -1; + } + if (s->listen_fd != -1) { + qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); + closesocket(s->listen_fd); + s->listen_fd = -1; + } +} + +static void net_stream_connect(void *opaque) +{ + NetStreamState *s = opaque; + net_stream_read_poll(s, true); +} + +static NetClientInfo net_stream_info = { + .type = NET_CLIENT_DRIVER_STREAM, + .size = sizeof(NetStreamState), + .receive = net_stream_receive, + .cleanup = net_stream_cleanup, +}; + +static NetStreamState *net_stream_fd_init(NetClientState *peer, + const char *model, + const char *name, + int fd, int is_connected) +{ + NetClientState *nc; + NetStreamState *s; + + nc = qemu_new_net_client(&net_stream_info, peer, model, name); + + qemu_set_info_str(nc, "fd=%d", fd); + + s = DO_UPCAST(NetStreamState, nc, nc); + + s->fd = fd; + s->listen_fd = -1; + net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); + + /* Disable Nagle algorithm on TCP sockets to reduce latency */ + socket_set_nodelay(fd); + + if (is_connected) { + net_stream_connect(s); + } else { + qemu_set_fd_handler(s->fd, NULL, net_stream_connect, s); + } + return s; +} + +static void net_stream_accept(void *opaque) +{ + NetStreamState *s = opaque; + struct sockaddr_in saddr; + socklen_t len; + int fd; + + for (;;) { + len = sizeof(saddr); + fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len); + if (fd < 0 && errno != EINTR) { + return; + } else if (fd >= 0) { + qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); + break; + } + } + + s->fd = fd; + s->nc.link_down = false; + net_stream_connect(s); + qemu_set_info_str(&s->nc, "connection from %s:%d", + inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); +} + +static int net_stream_server_init(NetClientState *peer, + const char *model, + const char *name, + SocketAddress *addr, + Error **errp) +{ + NetClientState *nc; + NetStreamState *s; + int fd, ret; + + switch (addr->type) { + case SOCKET_ADDRESS_TYPE_INET: { + struct sockaddr_in saddr_in; + + if (convert_host_port(&saddr_in, addr->u.inet.host, addr->u.inet.port, + errp) < 0) { + return -1; + } + + fd = qemu_socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create stream socket"); + return -1; + } + qemu_socket_set_nonblock(fd); + + socket_set_fast_reuse(fd); + + ret = bind(fd, (struct sockaddr *)&saddr_in, sizeof(saddr_in)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't bind ip=%s to socket", + inet_ntoa(saddr_in.sin_addr)); + closesocket(fd); + return -1; + } + break; + } + case SOCKET_ADDRESS_TYPE_FD: + fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp); + if (fd == -1) { + return -1; + } + ret = qemu_socket_try_set_nonblock(fd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + return -1; + } + break; + default: + error_setg(errp, "only support inet or fd type"); + return -1; + } + + ret = listen(fd, 0); + if (ret < 0) { + error_setg_errno(errp, errno, "can't listen on socket"); + closesocket(fd); + return -1; + } + + nc = qemu_new_net_client(&net_stream_info, peer, model, name); + s = DO_UPCAST(NetStreamState, nc, nc); + s->fd = -1; + s->listen_fd = fd; + s->nc.link_down = true; + net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); + + qemu_set_fd_handler(s->listen_fd, net_stream_accept, NULL, s); + return 0; +} + +static int net_stream_client_init(NetClientState *peer, + const char *model, + const char *name, + SocketAddress *addr, + Error **errp) +{ + NetStreamState *s; + struct sockaddr_in saddr_in; + int fd, connected, ret; + + switch (addr->type) { + case SOCKET_ADDRESS_TYPE_INET: + if (convert_host_port(&saddr_in, addr->u.inet.host, addr->u.inet.port, + errp) < 0) { + return -1; + } + + fd = qemu_socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create stream socket"); + return -1; + } + qemu_socket_set_nonblock(fd); + + connected = 0; + for (;;) { + ret = connect(fd, (struct sockaddr *)&saddr_in, sizeof(saddr_in)); + if (ret < 0) { + if (errno == EINTR || errno == EWOULDBLOCK) { + /* continue */ + } else if (errno == EINPROGRESS || + errno == EALREADY || + errno == EINVAL) { + break; + } else { + error_setg_errno(errp, errno, "can't connect socket"); + closesocket(fd); + return -1; + } + } else { + connected = 1; + break; + } + } + break; + case SOCKET_ADDRESS_TYPE_FD: + fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp); + if (fd == -1) { + return -1; + } + ret = qemu_socket_try_set_nonblock(fd); + if (ret < 0) { + error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", + name, fd); + return -1; + } + connected = 1; + break; + default: + error_setg(errp, "only support inet or fd type"); + return -1; + } + + s = net_stream_fd_init(peer, model, name, fd, connected); + + switch (addr->type) { + case SOCKET_ADDRESS_TYPE_INET: + qemu_set_info_str(&s->nc, "connect to %s:%d", + inet_ntoa(saddr_in.sin_addr), + ntohs(saddr_in.sin_port)); + break; + case SOCKET_ADDRESS_TYPE_FD: + qemu_set_info_str(&s->nc, "connect to fd %d", fd); + break; + default: + g_assert_not_reached(); + } + + return 0; +} + +int net_init_stream(const Netdev *netdev, const char *name, + NetClientState *peer, Error **errp) +{ + const NetdevStreamOptions *sock; + + assert(netdev->type == NET_CLIENT_DRIVER_STREAM); + sock = &netdev->u.stream; + + if (!sock->has_server || sock->server) { + return net_stream_server_init(peer, "stream", name, sock->addr, errp); + } + return net_stream_client_init(peer, "stream", name, sock->addr, errp); +} diff --git a/qapi/net.json b/qapi/net.json index dd088c09c509..eddd18340455 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -7,6 +7,7 @@ ## { 'include': 'common.json' } +{ 'include': 'sockets.json' } ## # @set_link: @@ -573,6 +574,60 @@ '*isolated': 'bool' }, 'if': 'CONFIG_VMNET' } +## +# @NetdevStreamOptions: +# +# Configuration info for stream socket netdev +# +# @addr: socket address to listen on (server=true) +# or connect to (server=false) +# @server: create server socket (default: true) +# +# Only SocketAddress types 'inet' and 'fd' are supported. +# +# Since: 7.1 +## +{ 'struct': 'NetdevStreamOptions', + 'data': { + 'addr': 'SocketAddress', + '*server': 'bool' } } + +## +# @NetdevDgramOptions: +# +# Configuration info for datagram socket netdev. +# +# @remote: remote address +# @local: local address +# +# Only SocketAddress types 'inet' and 'fd' are supported. +# +# If remote address is present and it's a multicast address, local address +# is optional. Otherwise local address is required and remote address is +# optional. +# +# .. table:: Valid parameters combination table +# :widths: auto +# +# ============= ======== ===== +# remote local okay? +# ============= ======== ===== +# absent absent no +# absent not fd no +# absent fd yes +# multicast absent yes +# multicast present yes +# not multicast absent no +# not multicast present yes +# ============= ======== ===== +# +# Since: 7.1 +## +{ 'struct': 'NetdevDgramOptions', + 'data': { + '*local': 'SocketAddress', + '*remote': 'SocketAddress' } } + ## # @NetClientDriver: # @@ -586,8 +641,9 @@ # @vmnet-bridged since 7.1 ## { 'enum': 'NetClientDriver', - 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', - 'bridge', 'hubport', 'netmap', 'vhost-user', 'vhost-vdpa', + 'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'stream', + 'dgram', 'vde', 'bridge', 'hubport', 'netmap', 'vhost-user', + 'vhost-vdpa', { 'name': 'vmnet-host', 'if': 'CONFIG_VMNET' }, { 'name': 'vmnet-shared', 'if': 'CONFIG_VMNET' }, { 'name': 'vmnet-bridged', 'if': 'CONFIG_VMNET' }] } @@ -617,6 +673,8 @@ 'tap': 'NetdevTapOptions', 'l2tpv3': 'NetdevL2TPv3Options', 'socket': 'NetdevSocketOptions', + 'stream': 'NetdevStreamOptions', + 'dgram': 'NetdevDgramOptions', 'vde': 'NetdevVdeOptions', 'bridge': 'NetdevBridgeOptions', 'hubport': 'NetdevHubPortOptions', diff --git a/qemu-options.hx b/qemu-options.hx index 913c71e38f2b..d5ef9202cbec 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2756,6 +2756,18 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, "-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n" " configure a network backend to connect to another network\n" " using an UDP tunnel\n" + "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port\n" + "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n" + " configure a network backend to connect to another network\n" + " using a socket connection in stream mode.\n" + "-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=inet,local.host=addr]\n" + "-netdev dgram,id=str,remote.type=inet,remote.host=maddr,remote.port=port[,local.type=fd,local.str=file-descriptor]\n" + " configure a network backend to connect to a multicast maddr and port\n" + " use ``local.host=addr`` to specify the host address to send packets from\n" + "-netdev dgram,id=str,local.type=inet,local.host=addr,local.port=port[,remote.type=inet,remote.host=addr,remote.port=port]\n" + "-netdev dgram,id=str,local.type=fd,local.str=file-descriptor\n" + " configure a network backend to connect to another network\n" + " using an UDP tunnel\n" #ifdef CONFIG_VDE "-netdev vde,id=str[,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n" " configure a network backend to connect to port 'n' of a vde switch\n" From patchwork Wed Oct 5 16:20:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999481 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 5EE18C433FE for ; Wed, 5 Oct 2022 16:53:34 +0000 (UTC) Received: from localhost ([::1]:42236 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7eH-0003h6-5U for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:53:33 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46936) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og795-0007R0-FO for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:19 -0400 Received: from mout.kundenserver.de ([212.227.17.10]:57205) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og790-0002oe-Ky for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:18 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MLA6m-1oyKTy0ViU-00ICAS; Wed, 05 Oct 2022 18:21:04 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" , Stefano Brivio Subject: [PATCH v10 07/17] net: socket: Don't ignore EINVAL on netdev socket connection Date: Wed, 5 Oct 2022 18:20:41 +0200 Message-Id: <20221005162051.1120041-8-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:FDJZof5MsbvXVo3Wv9lPKjTdT2JOJurWHTnVoaBaLKmfGQm9sGQ 3JQcoG/jqbY6k+wlmltLDmba+NDtptdo2rJviixE9xVrJVFRm1kl6IDyhLS509eO1aRqKCO mCS2x8nvSmaCRGNQy6+h+ptzrO+2UyVZ+N7E4orOCTasE1Qwi30c566ua62GuFWAd1dC1jG 53iGi/oRZseHr/W//2shg== X-UI-Out-Filterresults: notjunk:1;V03:K0:d1JOKwi9sEU=:2nFwCY/Lg3xJYH61F+96cT 214rqbYZNjDoHUbAccWwU3/S2FjTTku3qPxnrwe75smF9QuR0h7dQicqxI2u06k7HhGwb7V05 5z1jeJ1YPesZ2I5rWdnvalrCCz63bsV4DZ94NwgGskfr/io4Pn+2cGKwreBaaWSP5LvH7nzya wDbBsOYW425bA1nD15t7AjtWWnCIFsg5G9VuTClzQy5fXS34xWKJFDgVLx+OFDwTjUAn152U2 zGsCEaMn5lx6Ph+u2H3S/BoMWCc+iifmBbgnxewW4o2wsiqC0ScXyyB4RGoOJYHVIyvaGkjxm Gbe5ATZ26bdmPkOc5bESIFLqhVEmE2CAAYVASf3NVwFTcsBvMsbYMGmh2oveDaMjuExybOe7x aov4Kj0O+ja6atPKt0VzYKzg19L9ZAm5dS/q9/+rLx7QA+lwv2oDamsSGs27F6jfUAJVALRvd WDJVmqjnbdnv46aGT59JgFuwM4DcIlNUgY+LZM+FoY5QtPC/0UvRDT5Vrl+QWf4c4CA/xw+E3 WGkRwWBDvHtBfAvpLJTrDiO2BXUtBYAnaKILlYfxSrhYT1q7VMO/AfQgw9/sYVpZXk52EC1YP EcTrWRYIqM0Dod6aGdEHyukP9ywpcnoJrFmKvY1ozIZaYOp9qQQAuts2WwsrzUu/lJkmCEFJb tTZ9aYiSuWSPlKe1vPcZY+/hqVVSRbl2UNZZJ004E6tvp5vrvtZYEiBg/Yg6Wfa40H7JUjSF5 o0vzDRPqHHIjMIO3Dut4msloSYByE9WkbOUnkxbfGssXBbKHLd+Ry32wkkeDsIYkI7C9p7Qcm cTYNv4K Received-SPF: permerror client-ip=212.227.17.10; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Stefano Brivio Other errors are treated as failure by net_socket_connect_init(), but if connect() returns EINVAL, we'll fail silently. Remove the related exception. Signed-off-by: Stefano Brivio Signed-off-by: Laurent Vivier Reviewed-by: David Gibson --- net/socket.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/socket.c b/net/socket.c index ade1ecf38b87..4944bb70d580 100644 --- a/net/socket.c +++ b/net/socket.c @@ -577,8 +577,7 @@ static int net_socket_connect_init(NetClientState *peer, if (errno == EINTR || errno == EWOULDBLOCK) { /* continue */ } else if (errno == EINPROGRESS || - errno == EALREADY || - errno == EINVAL) { + errno == EALREADY) { break; } else { error_setg_errno(errp, errno, "can't connect socket"); From patchwork Wed Oct 5 16:20:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999479 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 7DDFFC433FE for ; Wed, 5 Oct 2022 16:45:08 +0000 (UTC) Received: from localhost ([::1]:45734 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7W7-0006P0-Av for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:45:07 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46926) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og794-0007P1-0l for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:18 -0400 Received: from mout.kundenserver.de ([212.227.17.13]:52517) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78x-0002o9-FU for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:17 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MKsax-1ouC9U14Pt-00LD6d; Wed, 05 Oct 2022 18:21:05 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" , Stefano Brivio Subject: [PATCH v10 08/17] net: stream: Don't ignore EINVAL on netdev socket connection Date: Wed, 5 Oct 2022 18:20:42 +0200 Message-Id: <20221005162051.1120041-9-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:DcdpaHZPyNUV4Su1+5cQn/Ctr2ur1utRwPQ+zSn0E3Iov4JH213 SI6d+Nrrt6ubRco4tVYqfN6nF1gkC+f1qBtCW39W1k9MOt33y8u+iNb0QjCbBSj5JkSP/2E LJqvZSVDJ6rWWHvFHzv4KD/yXP6qjtf66S4qrig3yWZxv9M/QVCgedNXiBUBrobHLfr/JPS BsDo1BL2dktUxyx2S4jTg== X-UI-Out-Filterresults: notjunk:1;V03:K0:0RgsTViv1IE=:9nkI0ECJ7gG5Iymb9xeIyI bhz3KafHPWdyQXw9d1QgfZdMw66tRGbJAb5cA83umezWn+DVGg69t5LbVWJKO2M9xDT9gBYzK lRQL9kGgh5QTMAK7JreTBgjYXCxOifsgetOnXKaT45ZOUs6hwlsB+tMVnFtXEOfKMxNx1qLs+ bXE1pM8o5g2CGsUXlgKCRx4MCSG+z5vXvBcoULWP7Mu2Y3RkhRTRjOqnIHFRNA4moF3lM92NM aYMfNakyODzWUIU/QL+KksFAyKXTvEqtmHseMHW02/Uq3Qx7uadCpybOrnGHN/9kgIgu/unBc NYQsQaGxQ6xCohcsUC0JyUvybbq8/ao1kgNMwxCCBcDkF4Ju1fsHMVEAKaPxyazz7+0emSAM0 BHGsIYBPr2AiEpkb5YyvmnrarTDL71neNMl22ePoKLmVr82sxVvp1CCLBB3RsbG6t5fpyXSf2 GMtm+G4+Fpz364v71lMrRrideyQc8bSfGV44fkBoikPQLzSZGcA1SJ9pD+NSU21OsEhYy8yQ8 N8wFAizslMtt0jWrFFoB64GjFbULVMwcu4tyz4/Gd1uNb+9RF4LPNUF34weVbSbogQnkaGQzH oujzr1N12PO4eWhkPQtUoNkQWq7o9AzVrl3Hb2xBbQ4S3B/chTaIJ9ggX4IxVZ6KSNJXBep4g h2kD7teLIqetXjGd8zpRFqJhaev7xpfXbP1Fiu03C6CcxSoC6g7MaVbFdBeVcN/8JZ7gSXiHS Zu/B8G9ebEs+VyWi10G50dKUfDtPB8qJT80dZ36u22U1C5hKMp1VPHUGyObtQocB2k0OZFuJe nrNfI3A Received-SPF: permerror client-ip=212.227.17.13; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, T_SPF_TEMPERROR=0.01 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" From: Stefano Brivio Other errors are treated as failure by net_stream_client_init(), but if connect() returns EINVAL, we'll fail silently. Remove the related exception. Signed-off-by: Stefano Brivio [lvivier: applied to net/stream.c] Signed-off-by: Laurent Vivier Reviewed-by: Daniel P. Berrangé Reviewed-by: David Gibson --- net/stream.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/stream.c b/net/stream.c index 37965eb74e1a..26e485438718 100644 --- a/net/stream.c +++ b/net/stream.c @@ -360,8 +360,7 @@ static int net_stream_client_init(NetClientState *peer, if (errno == EINTR || errno == EWOULDBLOCK) { /* continue */ } else if (errno == EINPROGRESS || - errno == EALREADY || - errno == EINVAL) { + errno == EALREADY) { break; } else { error_setg_errno(errp, errno, "can't connect socket"); From patchwork Wed Oct 5 16:20:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999439 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 614E7C433FE for ; Wed, 5 Oct 2022 16:28:59 +0000 (UTC) Received: from localhost ([::1]:39304 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7GT-0005Ks-Q0 for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:28:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:50408) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og791-0007Iz-96 for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:15 -0400 Received: from mout.kundenserver.de ([217.72.192.75]:54781) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78x-0002nw-Em for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:14 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MJV9S-1ovZb01iq8-00Jq3m; Wed, 05 Oct 2022 18:21:06 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" , Stefano Brivio Subject: [PATCH v10 09/17] net: stream: add unix socket Date: Wed, 5 Oct 2022 18:20:43 +0200 Message-Id: <20221005162051.1120041-10-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:wPXmfk+ou0awVYUqNCtz7+sACHvx2fz/wPVUkoMwbmX8nKT1W0D NTssiSWy3Rq150Kbo71G/xVF6rT2kJUkegf4YO8TYutKlo4xPRb+mCxuptk6Xl+fvxmrgQN lgbY6pDHuLqHtbFn0zqURct7iF4P3qmcqdEpTAOOEwgnbJIjoda3dkSVtweGlvqPsA70/ow CrdVYl0Fw5OxkcpBerbQQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:85OOCCLW/Xs=:qH2BKKVJV2FioaGX3uPl56 p9itqCYYMzjTdCeF4cW0xWcdK6MALQhpV9gz8IEym4oOrRC1Rci332317i8ctLxBrVobXzmWR hpp/WYUT/AYydyp5sYb2fyh9vR8Tb4TdtO3aQ6m/haZIiiTx1VKqFzc7kUTcLbzywstrTEUaC Qu6xim5C8yE/GQ/0c3Goq6lSqrRjoVUWkEz3ZGs7iDeaPhZQK7rC6cvKCBnbyx+rdB7OGMss8 Cv9rS57YBUtQRQWEu4bEsVQbOl8ZDJfD5j8RLSsW8K9+WIst0BKSIfsrkTW7dSuV8+71iGeBB Qt+4FZE1L+TaEdTBjWJiQQJtySz5wtI7rCb15Cy8781WP4oDwmN8JCYZfIwBur96AMpXhnaNw Iy0gdNqqglW2DsSbHodBE6IqaENKU0BaROfe97CYVLlxDZr5daD06iE74UNatAyAg794X2T9Y xb2rvKdU27flocJYIlNZ+7Q3ZLkB2YswhaDXxuaLbdv3bB5pzMkOvj/ky2Hj4MWM3DddUJxdL M7LvUMiCCUUPeEteIufQ8hEr/dUNClr5mosAD++rMqXSv+GOGR3XQWt7oek7WMo4raA5MlidV FOEYjYMi7HywEbJd6AjQqHVSlTb/tWO5VaMN531tVDt3GGEFOZtgkbjG4YeUgdTKhD1+qevPL 1X/U4r4/jQ5+fH/bbKRcI2OLj7yVY9YQtkQ351jIMPls5IfxHHFKbM5/isQv+vy1xOJRyX+Jf unGZSW6gjxfnwnuu1rwcwr2Oqd5I8eNnb0EFuZVI3YE9TJXSlnqJYDfiHH9LAGqq4RTKXHI5c EbfH00E Received-SPF: permerror client-ip=217.72.192.75; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Laurent Vivier Reviewed-by: Stefano Brivio --- net/stream.c | 107 +++++++++++++++++++++++++++++++++++++++++++++--- qapi/net.json | 2 +- qemu-options.hx | 1 + 3 files changed, 104 insertions(+), 6 deletions(-) diff --git a/net/stream.c b/net/stream.c index 26e485438718..d26c79d035fc 100644 --- a/net/stream.c +++ b/net/stream.c @@ -235,7 +235,7 @@ static NetStreamState *net_stream_fd_init(NetClientState *peer, static void net_stream_accept(void *opaque) { NetStreamState *s = opaque; - struct sockaddr_in saddr; + struct sockaddr_storage saddr; socklen_t len; int fd; @@ -253,8 +253,26 @@ static void net_stream_accept(void *opaque) s->fd = fd; s->nc.link_down = false; net_stream_connect(s); - qemu_set_info_str(&s->nc, "connection from %s:%d", - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + switch (saddr.ss_family) { + case AF_INET: { + struct sockaddr_in *saddr_in = (struct sockaddr_in *)&saddr; + + qemu_set_info_str(&s->nc, "connection from %s:%d", + inet_ntoa(saddr_in->sin_addr), + ntohs(saddr_in->sin_port)); + break; + } + case AF_UNIX: { + struct sockaddr_un saddr_un; + + len = sizeof(saddr_un); + getsockname(s->listen_fd, (struct sockaddr *)&saddr_un, &len); + qemu_set_info_str(&s->nc, "connect from %s", saddr_un.sun_path); + break; + } + default: + g_assert_not_reached(); + } } static int net_stream_server_init(NetClientState *peer, @@ -294,6 +312,43 @@ static int net_stream_server_init(NetClientState *peer, } break; } + case SOCKET_ADDRESS_TYPE_UNIX: { + struct sockaddr_un saddr_un; + + ret = unlink(addr->u.q_unix.path); + if (ret < 0 && errno != ENOENT) { + error_setg_errno(errp, errno, "failed to unlink socket %s", + addr->u.q_unix.path); + return -1; + } + + saddr_un.sun_family = PF_UNIX; + ret = snprintf(saddr_un.sun_path, sizeof(saddr_un.sun_path), "%s", + addr->u.q_unix.path); + if (ret < 0 || ret >= sizeof(saddr_un.sun_path)) { + error_setg(errp, "UNIX socket path '%s' is too long", + addr->u.q_unix.path); + error_append_hint(errp, "Path must be less than %zu bytes\n", + sizeof(saddr_un.sun_path)); + return -1; + } + + fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create stream socket"); + return -1; + } + qemu_socket_set_nonblock(fd); + + ret = bind(fd, (struct sockaddr *)&saddr_un, sizeof(saddr_un)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't create socket with path: %s", + saddr_un.sun_path); + closesocket(fd); + return -1; + } + break; + } case SOCKET_ADDRESS_TYPE_FD: fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp); if (fd == -1) { @@ -337,6 +392,7 @@ static int net_stream_client_init(NetClientState *peer, { NetStreamState *s; struct sockaddr_in saddr_in; + struct sockaddr_un saddr_un; int fd, connected, ret; switch (addr->type) { @@ -373,6 +429,45 @@ static int net_stream_client_init(NetClientState *peer, } } break; + case SOCKET_ADDRESS_TYPE_UNIX: + saddr_un.sun_family = PF_UNIX; + ret = snprintf(saddr_un.sun_path, sizeof(saddr_un.sun_path), "%s", + addr->u.q_unix.path); + if (ret < 0 || ret >= sizeof(saddr_un.sun_path)) { + error_setg(errp, "UNIX socket path '%s' is too long", + addr->u.q_unix.path); + error_append_hint(errp, "Path must be less than %zu bytes\n", + sizeof(saddr_un.sun_path)); + return -1; + } + + fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create stream socket"); + return -1; + } + qemu_socket_set_nonblock(fd); + + connected = 0; + for (;;) { + ret = connect(fd, (struct sockaddr *)&saddr_un, sizeof(saddr_un)); + if (ret < 0) { + if (errno == EINTR || errno == EWOULDBLOCK) { + /* continue */ + } else if (errno == EAGAIN || + errno == EALREADY) { + break; + } else { + error_setg_errno(errp, errno, "can't connect socket"); + closesocket(fd); + return -1; + } + } else { + connected = 1; + break; + } + } + break; case SOCKET_ADDRESS_TYPE_FD: fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp); if (fd == -1) { @@ -387,7 +482,7 @@ static int net_stream_client_init(NetClientState *peer, connected = 1; break; default: - error_setg(errp, "only support inet or fd type"); + error_setg(errp, "only support inet, unix or fd type"); return -1; } @@ -399,13 +494,15 @@ static int net_stream_client_init(NetClientState *peer, inet_ntoa(saddr_in.sin_addr), ntohs(saddr_in.sin_port)); break; + case SOCKET_ADDRESS_TYPE_UNIX: + qemu_set_info_str(&s->nc, " connect to %s", saddr_un.sun_path); + break; case SOCKET_ADDRESS_TYPE_FD: qemu_set_info_str(&s->nc, "connect to fd %d", fd); break; default: g_assert_not_reached(); } - return 0; } diff --git a/qapi/net.json b/qapi/net.json index eddd18340455..d8065c335072 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -583,7 +583,7 @@ # or connect to (server=false) # @server: create server socket (default: true) # -# Only SocketAddress types 'inet' and 'fd' are supported. +# Only SocketAddress types 'unix', 'inet' and 'fd' are supported. # # Since: 7.1 ## diff --git a/qemu-options.hx b/qemu-options.hx index d5ef9202cbec..95b231095542 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2757,6 +2757,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, " configure a network backend to connect to another network\n" " using an UDP tunnel\n" "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port\n" + "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path\n" "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n" " configure a network backend to connect to another network\n" " using a socket connection in stream mode.\n" From patchwork Wed Oct 5 16:20:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999478 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0F9B3C433F5 for ; Wed, 5 Oct 2022 16:43:45 +0000 (UTC) Received: from localhost ([::1]:49510 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7Um-0003U8-6F for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:43:44 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46934) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og795-0007Qz-Fn for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:19 -0400 Received: from mout.kundenserver.de ([212.227.17.10]:52501) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og790-0002oX-B5 for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:18 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1M3UhQ-1ogf6f2YZG-000fJg; Wed, 05 Oct 2022 18:21:07 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" , Stefano Brivio Subject: [PATCH v10 10/17] net: dgram: make dgram_dst generic Date: Wed, 5 Oct 2022 18:20:44 +0200 Message-Id: <20221005162051.1120041-11-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:CZs3QKOgMf4iXn5ieSDieZ5ZU9dtkDbt/mWcIZNQR7DRPR3S73w i2ngQUYTlkAfK80SkUzMKqX3J+8URaA7NBndv0TQdgyWZvNSlyg5Li5/ghXXKyD3tW6VUqb 4rF7TgvifODwMBOpNKD+NjQzjnl+774grwnnVIdhhPqola4aVsWrvr9oOma4acEJg/2UJSo zcWh/TmonY2PCkrrln2iQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:iT9cuer4eMU=:qYAO8jiKBT+d4Fr2EDareB l5zt7vawiDGsVkY6SZejD+vBtOYCXBOmfGP1nlHEGxBq3900U51V2iGEuIamM2M/hMixHIuDq WxzhwdllKhILMT97kbZuTc3jTeOTe2R9pTFDZXKggmcrMXcO6nl42i0bahK5NUVZ54dwiqvn4 xPT8kMoeqQQVJL5KQUWxvm2d1RISOsOEhoreVb17leJzX2tuuJe3yNGuvCXW12ecyNDjZBsRA P78AAO+qlCWBiLIljcvEvVZR/VAbZ5RO+pf9fUg2s0RENgBcBMtn/sJrYryKbJ5QxscN9gy44 QYc+guJ5M1IH8Wik/+IVnuOCyior3ncW53HVtntNPwdZKNw2D2pA00ahfRYQV9mQzgPdnd9qi htCzBO9f/+yvCiiZpmxC3YnypHbNwf5cP1wHLrbym28oFjrU7Yng6Z43uwiumrvmioyIGM/L4 lWXEBGAAt4Wba4a4wj9DoDR22iC1z+mExcYjOe6eN6zKEXWnGB0vOR4lxpah9g8r/7XRmUrLb zLhUKQf3WMWzJqdFD4G38BFcX09d8bGkNpwhz/BhSw6lTryNt72lzj+87gr1mia9QWXTFoG/L zezMsLHqJLjpna4oqNSkV3BxvhIRKBRDEop3X4fOdnKQypxO22Xq+NPSlwl8Xx8IUQ89QksN+ 91BmVfkhbM0jeay85SR0fSGLsPCilRhpygDesp66reeRQnwvefLtqW8LGmhfstWZvDMFSvjDI maO+jkPuIeIqjrh+EIxZVFiNmtP114R5ntuDzwE0xIVSZRGK/CDh4mENsBkLJ3jDeYpWsXDcf ZXXD8pc Received-SPF: permerror client-ip=212.227.17.10; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" dgram_dst is a sockaddr_in structure. To be able to use it with unix socket, use a pointer to a generic sockaddr structure. Rename it dest_addr, and store socket length in dest_len. Signed-off-by: Laurent Vivier Reviewed-by: Stefano Brivio --- net/dgram.c | 82 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/net/dgram.c b/net/dgram.c index 5339585b8202..e20be9ca79d3 100644 --- a/net/dgram.c +++ b/net/dgram.c @@ -40,9 +40,11 @@ typedef struct NetDgramState { NetClientState nc; int fd; SocketReadState rs; - struct sockaddr_in dgram_dst; /* contains destination iff connectionless */ bool read_poll; /* waiting to receive data? */ bool write_poll; /* waiting to transmit data? */ + /* contains destination iff connectionless */ + struct sockaddr *dest_addr; + socklen_t dest_len; } NetDgramState; static void net_dgram_send(void *opaque); @@ -84,10 +86,8 @@ static ssize_t net_dgram_receive(NetClientState *nc, ssize_t ret; do { - if (s->dgram_dst.sin_family != AF_UNIX) { - ret = sendto(s->fd, buf, size, 0, - (struct sockaddr *)&s->dgram_dst, - sizeof(s->dgram_dst)); + if (s->dest_addr) { + ret = sendto(s->fd, buf, size, 0, s->dest_addr, s->dest_len); } else { ret = send(s->fd, buf, size, 0); } @@ -244,6 +244,9 @@ static void net_dgram_cleanup(NetClientState *nc) close(s->fd); s->fd = -1; } + g_free(s->dest_addr); + s->dest_addr = NULL; + s->dest_len = 0; } static NetClientInfo net_dgram_socket_info = { @@ -260,7 +263,7 @@ static NetDgramState *net_dgram_fd_init(NetClientState *peer, SocketAddress *mcast, Error **errp) { - struct sockaddr_in saddr; + struct sockaddr_in *saddr = NULL; int newfd; NetClientState *nc; NetDgramState *s; @@ -275,31 +278,32 @@ static NetDgramState *net_dgram_fd_init(NetClientState *peer, qapi_free_SocketAddress(sa); /* - * fd passed: multicast: "learn" dgram_dst address from bound address and + * fd passed: multicast: "learn" dest_addr address from bound address and * save it. Because this may be "shared" socket from a "master" process, * datagrams would be recv() by ONLY ONE process: we must "clone" this * dgram socket --jjo */ if (is_fd && mcast != NULL) { - if (convert_host_port(&saddr, mcast->u.inet.host, - mcast->u.inet.port, errp) < 0) { + saddr = g_new(struct sockaddr_in, 1); + + if (convert_host_port(saddr, mcast->u.inet.host, mcast->u.inet.port, + errp) < 0) { goto err; } /* must be bound */ - if (saddr.sin_addr.s_addr == 0) { + if (saddr->sin_addr.s_addr == 0) { error_setg(errp, "can't setup multicast destination address"); goto err; } /* clone dgram socket */ - newfd = net_dgram_mcast_create(&saddr, NULL, errp); + newfd = net_dgram_mcast_create(saddr, NULL, errp); if (newfd < 0) { goto err; } /* clone newfd to fd, close newfd */ dup2(newfd, fd); close(newfd); - } nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name); @@ -311,21 +315,20 @@ static NetDgramState *net_dgram_fd_init(NetClientState *peer, net_dgram_read_poll(s, true); /* mcast: save bound address as dst */ - if (is_fd && mcast != NULL) { - s->dgram_dst = saddr; + if (saddr) { + g_assert(s->dest_addr == NULL); + s->dest_addr = (struct sockaddr *)saddr; + s->dest_len = sizeof(*saddr); qemu_set_info_str(nc, "fd=%d (cloned mcast=%s:%d)", fd, - inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); + inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); } else { - if (sa_type == SOCKET_ADDRESS_TYPE_UNIX) { - s->dgram_dst.sin_family = AF_UNIX; - } - qemu_set_info_str(nc, "fd=%d %s", fd, SocketAddressType_str(sa_type)); } return s; err: + g_free(saddr); closesocket(fd); return NULL; } @@ -339,21 +342,24 @@ static int net_dgram_mcast_init(NetClientState *peer, { NetDgramState *s; int fd, ret; - struct sockaddr_in saddr; + struct sockaddr_in *saddr; if (remote->type != SOCKET_ADDRESS_TYPE_INET) { error_setg(errp, "multicast only support inet type"); return -1; } - if (convert_host_port(&saddr, remote->u.inet.host, remote->u.inet.port, + saddr = g_new(struct sockaddr_in, 1); + if (convert_host_port(saddr, remote->u.inet.host, remote->u.inet.port, errp) < 0) { + g_free(saddr); return -1; } if (!local) { - fd = net_dgram_mcast_create(&saddr, NULL, errp); + fd = net_dgram_mcast_create(saddr, NULL, errp); if (fd < 0) { + g_free(saddr); return -1; } } else { @@ -362,13 +368,15 @@ static int net_dgram_mcast_init(NetClientState *peer, struct in_addr localaddr; if (inet_aton(local->u.inet.host, &localaddr) == 0) { + g_free(saddr); error_setg(errp, "localaddr '%s' is not a valid IPv4 address", local->u.inet.host); return -1; } - fd = net_dgram_mcast_create(&saddr, &localaddr, errp); + fd = net_dgram_mcast_create(saddr, &localaddr, errp); if (fd < 0) { + g_free(saddr); return -1; } break; @@ -376,16 +384,19 @@ static int net_dgram_mcast_init(NetClientState *peer, case SOCKET_ADDRESS_TYPE_FD: fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp); if (fd == -1) { + g_free(saddr); return -1; } ret = qemu_socket_try_set_nonblock(fd); if (ret < 0) { + g_free(saddr); error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", name, fd); return -1; } break; default: + g_free(saddr); error_setg(errp, "only support inet or fd type for local"); return -1; } @@ -395,13 +406,17 @@ static int net_dgram_mcast_init(NetClientState *peer, local->type == SOCKET_ADDRESS_TYPE_FD, remote, errp); if (!s) { + g_free(saddr); return -1; } - s->dgram_dst = saddr; + g_assert(s->dest_addr == NULL); + s->dest_addr = (struct sockaddr *)saddr; + s->dest_len = sizeof(*saddr); + + qemu_set_info_str(&s->nc, "mcast=%s:%d", inet_ntoa(saddr->sin_addr), + ntohs(saddr->sin_port)); - qemu_set_info_str(&s->nc, "mcast=%s:%d", inet_ntoa(saddr.sin_addr), - ntohs(saddr.sin_port)); return 0; } @@ -412,9 +427,10 @@ int net_init_dgram(const Netdev *netdev, const char *name, { NetDgramState *s; int fd, ret; - struct sockaddr_in raddr_in; - struct sockaddr_in laddr_in; SocketAddress *remote, *local; + struct sockaddr *dest_addr; + struct sockaddr_in laddr_in, raddr_in; + socklen_t dest_len; assert(netdev->type == NET_CLIENT_DRIVER_DGRAM); @@ -491,6 +507,10 @@ int net_init_dgram(const Netdev *netdev, const char *name, return -1; } qemu_socket_set_nonblock(fd); + + dest_len = sizeof(raddr_in); + dest_addr = g_malloc(dest_len); + memcpy(dest_addr, &raddr_in, dest_len); break; case SOCKET_ADDRESS_TYPE_FD: fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp); @@ -503,6 +523,8 @@ int net_init_dgram(const Netdev *netdev, const char *name, name, fd); return -1; } + dest_addr = NULL; + dest_len = 0; break; default: error_setg(errp, "only support inet or fd type for local"); @@ -515,7 +537,9 @@ int net_init_dgram(const Netdev *netdev, const char *name, } if (remote) { - s->dgram_dst = raddr_in; + g_assert(s->dest_addr == NULL); + s->dest_addr = dest_addr; + s->dest_len = dest_len; } switch (local->type) { From patchwork Wed Oct 5 16:20:45 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999471 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0DDA3C433F5 for ; Wed, 5 Oct 2022 16:41:16 +0000 (UTC) Received: from localhost ([::1]:40454 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7SO-0000w5-1f for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:41:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46922) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og793-0007Nc-9p for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:17 -0400 Received: from mout.kundenserver.de ([212.227.17.10]:55405) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78z-0002oU-Ik for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:16 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1M89P3-1oc0P93Oz5-005MHh; Wed, 05 Oct 2022 18:21:09 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" , Stefano Brivio Subject: [PATCH v10 11/17] net: dgram: move mcast specific code from net_socket_fd_init_dgram() Date: Wed, 5 Oct 2022 18:20:45 +0200 Message-Id: <20221005162051.1120041-12-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:IvuF7w06XoFhRCv/fcKtlSy5lukeRfAD2QQL2Bcjybld9zU34sT V/6a64dtHEKjx9xsc/B7ONutEYhWHcS8qyoVQri59dj9IikXQc0hsDkdSqm7wtC8Z942MCd Ac34YQcaCbNKJLFaiJ4kCt5LI7N0TCqWiU1Q2PWxu38VZB/1M1TI4vLM+lKCJNEtUwFAFlQ f5HNOj4psSg64TZWUNw2Q== X-UI-Out-Filterresults: notjunk:1;V03:K0:aS1rsLwQ/yA=:EFXM2ULlCT3c44NFx7r4sF e9cyn4CrKkNbxBgICLtOjsHdDTC05272S4xOawHuEPEmXgcbtOD15BFjRceeWpwSO14E4Jgny fNMC55XP6WBEhl+DYEgwb5ehoUCH2dJwZCHj0PAiyyVObazeuwjPk84HXTXDdP6Uhd0oTOrLh ot+UP9ZcB4aKfSwU+U9ES7QBxKey5GZg30tFlX5pWYrMvkHs7n+WBM3uynYjgqT6t2S23zqVO IXZ6xxTfLwfQdmyD/IeEiZCfwerBmxAIaNiot40t3d0xbsxXbH1olDkKgKl6CORi3Yt/l01lH AWxeio4x5ZIYpwniWTcWhlOC6f0hFuoXH8Avs6r4lPXXtHXOtvwnTFB7O8U5dk46XOlzWO/Y8 VQ/ETF3elBlSejbYlWBmGfID8jXoj7FEmxuPVt6BncPfn9xa3wPkMiVOUNP5IqUI72Q694GFX fmawJzAt2iVietf/47mn3sBZeX2TI7V55l7DXOVEsfLPSqcJFrnHebvFE/v4T17PTZjGcnoId nC7kqF29FdwOIxojTkfyGAmugx6TkZPrJpUTIT4C3ern7iGaDr233bT/zmJHYzouL+XeYhiVR PbgeqMfNzOKToSOkYXTTV0WbI4J7hsWgaW9eZ6TKfn3xxo8TZrAYAPG8xpuA3e10V7nQsFd6w ICmcR2m4A9xPNCnnQ8myOkVvTzhtEBf1G5YzvrXb1EvodrIXSHOcV9uwyLPFM/KZHA1SeeIEy Gts0P0eqPBTet543oWDPwQxclet5u1XttspokEhsYro0rJUgHhW8/mJlz+/RdM2wwBUnCx696 pxUrC9t Received-SPF: permerror client-ip=212.227.17.10; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" It is less complex to manage special cases directly in net_dgram_mcast_init() and net_dgram_udp_init(). Signed-off-by: Laurent Vivier Reviewed-by: Stefano Brivio --- net/dgram.c | 143 ++++++++++++++++++++++++++++------------------------ 1 file changed, 76 insertions(+), 67 deletions(-) diff --git a/net/dgram.c b/net/dgram.c index e20be9ca79d3..e581cc62f39f 100644 --- a/net/dgram.c +++ b/net/dgram.c @@ -259,52 +259,11 @@ static NetClientInfo net_dgram_socket_info = { static NetDgramState *net_dgram_fd_init(NetClientState *peer, const char *model, const char *name, - int fd, int is_fd, - SocketAddress *mcast, + int fd, Error **errp) { - struct sockaddr_in *saddr = NULL; - int newfd; NetClientState *nc; NetDgramState *s; - SocketAddress *sa; - SocketAddressType sa_type; - - sa = socket_local_address(fd, errp); - if (!sa) { - return NULL; - } - sa_type = sa->type; - qapi_free_SocketAddress(sa); - - /* - * fd passed: multicast: "learn" dest_addr address from bound address and - * save it. Because this may be "shared" socket from a "master" process, - * datagrams would be recv() by ONLY ONE process: we must "clone" this - * dgram socket --jjo - */ - - if (is_fd && mcast != NULL) { - saddr = g_new(struct sockaddr_in, 1); - - if (convert_host_port(saddr, mcast->u.inet.host, mcast->u.inet.port, - errp) < 0) { - goto err; - } - /* must be bound */ - if (saddr->sin_addr.s_addr == 0) { - error_setg(errp, "can't setup multicast destination address"); - goto err; - } - /* clone dgram socket */ - newfd = net_dgram_mcast_create(saddr, NULL, errp); - if (newfd < 0) { - goto err; - } - /* clone newfd to fd, close newfd */ - dup2(newfd, fd); - close(newfd); - } nc = qemu_new_net_client(&net_dgram_socket_info, peer, model, name); @@ -314,23 +273,7 @@ static NetDgramState *net_dgram_fd_init(NetClientState *peer, net_socket_rs_init(&s->rs, net_dgram_rs_finalize, false); net_dgram_read_poll(s, true); - /* mcast: save bound address as dst */ - if (saddr) { - g_assert(s->dest_addr == NULL); - s->dest_addr = (struct sockaddr *)saddr; - s->dest_len = sizeof(*saddr); - qemu_set_info_str(nc, "fd=%d (cloned mcast=%s:%d)", fd, - inet_ntoa(saddr->sin_addr), ntohs(saddr->sin_port)); - } else { - qemu_set_info_str(nc, "fd=%d %s", fd, SocketAddressType_str(sa_type)); - } - return s; - -err: - g_free(saddr); - closesocket(fd); - return NULL; } static int net_dgram_mcast_init(NetClientState *peer, @@ -381,7 +324,9 @@ static int net_dgram_mcast_init(NetClientState *peer, } break; } - case SOCKET_ADDRESS_TYPE_FD: + case SOCKET_ADDRESS_TYPE_FD: { + int newfd; + fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp); if (fd == -1) { g_free(saddr); @@ -394,7 +339,42 @@ static int net_dgram_mcast_init(NetClientState *peer, name, fd); return -1; } + + /* + * fd passed: multicast: "learn" dest_addr address from bound + * address and save it. Because this may be "shared" socket from a + * "master" process, datagrams would be recv() by ONLY ONE process: + * we must "clone" this dgram socket --jjo + */ + + saddr = g_new(struct sockaddr_in, 1); + + if (convert_host_port(saddr, local->u.inet.host, local->u.inet.port, + errp) < 0) { + g_free(saddr); + closesocket(fd); + return -1; + } + + /* must be bound */ + if (saddr->sin_addr.s_addr == 0) { + error_setg(errp, "can't setup multicast destination address"); + g_free(saddr); + closesocket(fd); + return -1; + } + /* clone dgram socket */ + newfd = net_dgram_mcast_create(saddr, NULL, errp); + if (newfd < 0) { + g_free(saddr); + closesocket(fd); + return -1; + } + /* clone newfd to fd, close newfd */ + dup2(newfd, fd); + close(newfd); break; + } default: g_free(saddr); error_setg(errp, "only support inet or fd type for local"); @@ -402,9 +382,7 @@ static int net_dgram_mcast_init(NetClientState *peer, } } - s = net_dgram_fd_init(peer, model, name, fd, - local->type == SOCKET_ADDRESS_TYPE_FD, - remote, errp); + s = net_dgram_fd_init(peer, model, name, fd, errp); if (!s) { g_free(saddr); return -1; @@ -414,8 +392,26 @@ static int net_dgram_mcast_init(NetClientState *peer, s->dest_addr = (struct sockaddr *)saddr; s->dest_len = sizeof(*saddr); - qemu_set_info_str(&s->nc, "mcast=%s:%d", inet_ntoa(saddr->sin_addr), - ntohs(saddr->sin_port)); + if (!local) { + qemu_set_info_str(&s->nc, "mcast=%s:%d", + inet_ntoa(saddr->sin_addr), + ntohs(saddr->sin_port)); + } else { + switch (local->type) { + case SOCKET_ADDRESS_TYPE_INET: + qemu_set_info_str(&s->nc, "mcast=%s:%d", + inet_ntoa(saddr->sin_addr), + ntohs(saddr->sin_port)); + break; + case SOCKET_ADDRESS_TYPE_FD: + qemu_set_info_str(&s->nc, "fd=%d (cloned mcast=%s:%d)", + fd, inet_ntoa(saddr->sin_addr), + ntohs(saddr->sin_port)); + break; + default: + g_assert_not_reached(); + } + } return 0; @@ -531,7 +527,7 @@ int net_init_dgram(const Netdev *netdev, const char *name, return -1; } - s = net_dgram_fd_init(peer, "dgram", name, fd, 0, NULL, errp); + s = net_dgram_fd_init(peer, "dgram", name, fd, errp); if (!s) { return -1; } @@ -550,9 +546,22 @@ int net_init_dgram(const Netdev *netdev, const char *name, inet_ntoa(raddr_in.sin_addr), ntohs(raddr_in.sin_port)); break; - case SOCKET_ADDRESS_TYPE_FD: - qemu_set_info_str(&s->nc, "fd=%d", fd); + case SOCKET_ADDRESS_TYPE_FD: { + SocketAddress *sa; + SocketAddressType sa_type; + + sa = socket_local_address(fd, errp); + if (sa) { + sa_type = sa->type; + qapi_free_SocketAddress(sa); + + qemu_set_info_str(&s->nc, "fd=%d %s", fd, + SocketAddressType_str(sa_type)); + } else { + qemu_set_info_str(&s->nc, "fd=%d", fd); + } break; + } default: g_assert_not_reached(); } From patchwork Wed Oct 5 16:20:46 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999470 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 51FCFC433F5 for ; Wed, 5 Oct 2022 16:41:13 +0000 (UTC) Received: from localhost ([::1]:40452 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7SK-0000rQ-BZ for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:41:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46940) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og796-0007SM-33 for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:20 -0400 Received: from mout.kundenserver.de ([217.72.192.73]:40995) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og791-0002pC-2z for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:19 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MjSHc-1p4gBT4AZe-00kxPs; Wed, 05 Oct 2022 18:21:10 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" , Stefano Brivio Subject: [PATCH v10 12/17] net: dgram: add unix socket Date: Wed, 5 Oct 2022 18:20:46 +0200 Message-Id: <20221005162051.1120041-13-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:9mW5BjYZsTrgrCThoia1OPKqH2KDGXaDKQlaJZ4BEWNkWh5yydq 94wyBB2yvRx1r8UVV/oYtHfW1B0IeueDLDj8R84H54pqpOsZcdinrjp5w0KZBlso+FV/Q00 SuKbBV6NF/UpNeoaRi/hWavIfXrvCFdltUXqUTe2R7ylCtxen04+S9f36r2NbOf7sxBkCmW 5jtCUE31V5qM5DlaCApfA== X-UI-Out-Filterresults: notjunk:1;V03:K0:TdT+ES3sRYM=:kV/5ApdlVAx011nCwqeidQ /tKMtccIhWe9p9OnDhbTKCji80gEyej53MFcdAYh4zyjfqW4dwSbye9Ylzdr3ohrKKuAQoqg3 MCoypw885ilOADoK4hSU0lBHGcR+pGJz7tlHpMR/LdESQ9TJRnoqfUPtsPZPs2eZsqVu9kIBh yzl+BegyIhiP8+dbheWBGBgcurzuDeQbXmj56+Ylg+d/SPdb8CEEVB/w+VvbWvc/+YFHUDqEA C/7EZFRQAuwlPLiH/bNT8iSbxv6L0r1MuxVqJSvSec3eLEBBtXxXQVylnqfOKqcjkfEz7+tOQ WrXSwPlc9TIAnKVtJfzcE/SXZisOdLqn8VhZ2uDx80Mj3bynvf6otb0cigdZrmyMU3tBt9LmG LHB1yUD39zB7+vXaS3SWtNqV/T08d3JJyF1Iio+svg+w/U5TgGn04yR5caJ44GWyDC/jIkHsz RSOsS3CwWXUJgTfTCi4d+kDjgsxcHIU2n8VF+M8WhcMLxVBaPzjj64TA0pwiouea50lxtTK94 uxLN1bG121fpuWmE3fykvTfqarCcYXeDz7V51SG6jJvrctE4QD5d4sdKazab26Wt8Q6YvKoLA mlzzUbeNUBx5dSx8ZlTlfGrnSbJh3QVy64fcWNlXwi5A18/UrUmLfyTCnpf4pUrrBbcUEFD8t RwDsbC3xmJJu7SElxd0BRcin0XcgIkoMqxFYy463zsXX/jNJcjTZvYMSIm2TWesMvFDc8Lybd ec+mmmncb0FIbk4osoKxYvVG6UNaMnm2Jk4ZeeqrH3fOHDT56NRazh5InymCupijC5rydPMfe 49pnCp+ Received-SPF: permerror client-ip=217.72.192.73; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Laurent Vivier Reviewed-by: Stefano Brivio Reviewed-by: David Gibson --- net/dgram.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++- qapi/net.json | 2 +- qemu-options.hx | 1 + 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/net/dgram.c b/net/dgram.c index e581cc62f39f..02a189e36358 100644 --- a/net/dgram.c +++ b/net/dgram.c @@ -426,6 +426,7 @@ int net_init_dgram(const Netdev *netdev, const char *name, SocketAddress *remote, *local; struct sockaddr *dest_addr; struct sockaddr_in laddr_in, raddr_in; + struct sockaddr_un laddr_un, raddr_un; socklen_t dest_len; assert(netdev->type == NET_CLIENT_DRIVER_DGRAM); @@ -465,7 +466,7 @@ int net_init_dgram(const Netdev *netdev, const char *name, } } else { if (local->type != SOCKET_ADDRESS_TYPE_FD) { - error_setg(errp, "type=inet requires remote parameter"); + error_setg(errp, "type=inet or unix require remote parameter"); return -1; } } @@ -508,6 +509,53 @@ int net_init_dgram(const Netdev *netdev, const char *name, dest_addr = g_malloc(dest_len); memcpy(dest_addr, &raddr_in, dest_len); break; + case SOCKET_ADDRESS_TYPE_UNIX: + ret = unlink(local->u.q_unix.path); + if (ret < 0 && errno != ENOENT) { + error_setg_errno(errp, errno, "failed to unlink socket %s", + local->u.q_unix.path); + return -1; + } + + laddr_un.sun_family = PF_UNIX; + ret = snprintf(laddr_un.sun_path, sizeof(laddr_un.sun_path), "%s", + local->u.q_unix.path); + if (ret < 0 || ret >= sizeof(laddr_un.sun_path)) { + error_setg(errp, "UNIX socket path '%s' is too long", + local->u.q_unix.path); + error_append_hint(errp, "Path must be less than %zu bytes\n", + sizeof(laddr_un.sun_path)); + } + + raddr_un.sun_family = PF_UNIX; + ret = snprintf(raddr_un.sun_path, sizeof(raddr_un.sun_path), "%s", + remote->u.q_unix.path); + if (ret < 0 || ret >= sizeof(raddr_un.sun_path)) { + error_setg(errp, "UNIX socket path '%s' is too long", + remote->u.q_unix.path); + error_append_hint(errp, "Path must be less than %zu bytes\n", + sizeof(raddr_un.sun_path)); + } + + fd = qemu_socket(PF_UNIX, SOCK_DGRAM, 0); + if (fd < 0) { + error_setg_errno(errp, errno, "can't create datagram socket"); + return -1; + } + + ret = bind(fd, (struct sockaddr *)&laddr_un, sizeof(laddr_un)); + if (ret < 0) { + error_setg_errno(errp, errno, "can't bind unix=%s to socket", + laddr_un.sun_path); + closesocket(fd); + return -1; + } + qemu_socket_set_nonblock(fd); + + dest_len = sizeof(raddr_un); + dest_addr = g_malloc(dest_len); + memcpy(dest_addr, &raddr_un, dest_len); + break; case SOCKET_ADDRESS_TYPE_FD: fd = monitor_fd_param(monitor_cur(), local->u.fd.str, errp); if (fd == -1) { @@ -546,6 +594,10 @@ int net_init_dgram(const Netdev *netdev, const char *name, inet_ntoa(raddr_in.sin_addr), ntohs(raddr_in.sin_port)); break; + case SOCKET_ADDRESS_TYPE_UNIX: + qemu_set_info_str(&s->nc, "udp=%s:%s", + laddr_un.sun_path, raddr_un.sun_path); + break; case SOCKET_ADDRESS_TYPE_FD: { SocketAddress *sa; SocketAddressType sa_type; diff --git a/qapi/net.json b/qapi/net.json index d8065c335072..14d1531536c5 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -600,7 +600,7 @@ # @remote: remote address # @local: local address # -# Only SocketAddress types 'inet' and 'fd' are supported. +# Only SocketAddress types 'unix', 'inet' and 'fd' are supported. # # If remote address is present and it's a multicast address, local address # is optional. Otherwise local address is required and remote address is diff --git a/qemu-options.hx b/qemu-options.hx index 95b231095542..1111e02a220c 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2766,6 +2766,7 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, " configure a network backend to connect to a multicast maddr and port\n" " use ``local.host=addr`` to specify the host address to send packets from\n" "-netdev dgram,id=str,local.type=inet,local.host=addr,local.port=port[,remote.type=inet,remote.host=addr,remote.port=port]\n" + "-netdev dgram,id=str,local.type=unix,local.path=path[,remote.type=unix,remote.path=path]\n" "-netdev dgram,id=str,local.type=fd,local.str=file-descriptor\n" " configure a network backend to connect to another network\n" " using an UDP tunnel\n" From patchwork Wed Oct 5 16:20:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999467 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 6818DC433FE for ; Wed, 5 Oct 2022 16:37:17 +0000 (UTC) Received: from localhost ([::1]:60248 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7OW-0003Ty-H6 for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:37:16 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46932) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og794-0007Q1-RN for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:18 -0400 Received: from mout.kundenserver.de ([212.227.17.10]:40531) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og78z-0002oc-OX for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:18 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MUXlG-1oowoZ0amm-00QPd4; Wed, 05 Oct 2022 18:21:11 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" Subject: [PATCH v10 13/17] qemu-sockets: move and rename SocketAddress_to_str() Date: Wed, 5 Oct 2022 18:20:47 +0200 Message-Id: <20221005162051.1120041-14-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:1jrF0lL6Ohw0YL2pOK3R/rMugbDpDLwEW4OfibX+WkjEqLXnTPW 8NJr08YJ8OUo5nKwpSmigx2qUOeS5qbsQ/TTpOtpU64Frz9qcwlTgLd10EcxjrxpzljkS/j PaQvnPEKs1RKmKjdAl3R2NIL4bl4nGMWRHBM25Y6GLdBB0n5Z4ZwAhTI2RhnwdEuKvDHrCA J7I17NNrG1dqLYl6+yCkw== X-UI-Out-Filterresults: notjunk:1;V03:K0:qGaD+3oiPTw=:n+lL7NEbGLu5OoWogHacfv 4a21LmklN12v/l1MoXCF07Z0E7TtwaQmcBKbS8RZDYdfpCqMgIDQCwbWlGUdCLUQ5jQXam3GO z2grcd7OtbYH5YoOeDVV3lUCwTv3jWlto8ad17/YeVU08cGbXmWE06v3zsVbGHrX/vUUnKXi9 5VWPOLWLAbxaznSlwV2YlD6lFJ9/fqN+5dbfv4RtPpXLsBL2VUQ8GiJH/p2L0dI/JYkcAkcbD 9WZbUK3pO95XKDbzzvsLKFGD5DVwuMlF9Lb4ipJnq5lqLdXrSYhvgWm2bx2ecCaPUs7TbsS8g bFI1AMLPxqgbZSmRADos9JMc4jciHUR0CDgW/zauFuoGG4fbfusg6PSKCAxJcjQ3YdrSVfYD+ qdsnwe30qB3KzIHiNYdFlyuD+fiwpBr5xwr1LWdGKlgSS3oudxPpyeIk+b3260vU/7elAwLvn SPk3FcQ5Fr3443OQ5W335Z5RtFKGMAmoZJPk4Mk6WJDgSYgXWBl17ACgpdd878egks1TL5fRp x6yREDt261szj0jCotDrowHyW+vK2vJXBPpT7ZGUo1WnefHc3ZwRxQxITFK9ZMaH7ahG5hs8R DWvPNng7gaRMbT5pT8LIi7mw4VUsaW+jgR9UFWq7SoK+8tfvKLSfcpPyLtQZJqhLshi0iR9fA cQvbZkl1gJBf96IE+pLF0UYHMOfITF1hVWyk01NKa5uItMv2MteaK/HIUDQDkO3bYfFFMug/e E261NuOHm398WwOeBZVGHo/V0G8VIz1R/k6lXNGTULSYQfPNf+uShU8HF6cWo45dBaL6xjIaQ Hv6rCmb Received-SPF: permerror client-ip=212.227.17.10; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Rename SocketAddress_to_str() to socket_uri() and move it to util/qemu-sockets.c close to socket_parse(). socket_uri() generates a string from a SocketAddress while socket_parse() generates a SocketAddress from a string. Signed-off-by: Laurent Vivier Reviewed-by: David Gibson Reviewed-by: Dr. David Alan Gilbert --- include/qemu/sockets.h | 2 +- monitor/hmp-cmds.c | 23 +---------------------- util/qemu-sockets.c | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index db4bedb6fa20..214058d8e307 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -58,6 +58,7 @@ NetworkAddressFamily inet_netfamily(int family); int unix_listen(const char *path, Error **errp); int unix_connect(const char *path, Error **errp); +char *socket_uri(SocketAddress *addr); SocketAddress *socket_parse(const char *str, Error **errp); int socket_connect(SocketAddress *addr, Error **errp); int socket_listen(SocketAddress *addr, int num, Error **errp); @@ -141,5 +142,4 @@ SocketAddress *socket_address_flatten(SocketAddressLegacy *addr); * Return 0 on success. */ int socket_address_parse_named_fd(SocketAddress *addr, Error **errp); - #endif /* QEMU_SOCKETS_H */ diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index c6cd6f91dde6..cb35059c2d45 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -197,27 +197,6 @@ void hmp_info_mice(Monitor *mon, const QDict *qdict) qapi_free_MouseInfoList(mice_list); } -static char *SocketAddress_to_str(SocketAddress *addr) -{ - switch (addr->type) { - case SOCKET_ADDRESS_TYPE_INET: - return g_strdup_printf("tcp:%s:%s", - addr->u.inet.host, - addr->u.inet.port); - case SOCKET_ADDRESS_TYPE_UNIX: - return g_strdup_printf("unix:%s", - addr->u.q_unix.path); - case SOCKET_ADDRESS_TYPE_FD: - return g_strdup_printf("fd:%s", addr->u.fd.str); - case SOCKET_ADDRESS_TYPE_VSOCK: - return g_strdup_printf("tcp:%s:%s", - addr->u.vsock.cid, - addr->u.vsock.port); - default: - return g_strdup("unknown address type"); - } -} - void hmp_info_migrate(Monitor *mon, const QDict *qdict) { MigrationInfo *info; @@ -380,7 +359,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) monitor_printf(mon, "socket address: [\n"); for (addr = info->socket_address; addr; addr = addr->next) { - char *s = SocketAddress_to_str(addr->value); + char *s = socket_uri(addr->value); monitor_printf(mon, "\t%s\n", s); g_free(s); } diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 83f4bd6fd211..9f6f655fd526 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -1077,6 +1077,26 @@ int unix_connect(const char *path, Error **errp) return sock; } +char *socket_uri(SocketAddress *addr) +{ + switch (addr->type) { + case SOCKET_ADDRESS_TYPE_INET: + return g_strdup_printf("tcp:%s:%s", + addr->u.inet.host, + addr->u.inet.port); + case SOCKET_ADDRESS_TYPE_UNIX: + return g_strdup_printf("unix:%s", + addr->u.q_unix.path); + case SOCKET_ADDRESS_TYPE_FD: + return g_strdup_printf("fd:%s", addr->u.fd.str); + case SOCKET_ADDRESS_TYPE_VSOCK: + return g_strdup_printf("tcp:%s:%s", + addr->u.vsock.cid, + addr->u.vsock.port); + default: + return g_strdup("unknown address type"); + } +} SocketAddress *socket_parse(const char *str, Error **errp) { From patchwork Wed Oct 5 16:20:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999480 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 9D066C433FE for ; Wed, 5 Oct 2022 16:46:23 +0000 (UTC) Received: from localhost ([::1]:40044 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7XK-00071N-NS for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:46:22 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46938) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og795-0007Ra-Nw for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:20 -0400 Received: from mout.kundenserver.de ([212.227.17.24]:55049) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og790-0002pA-SB for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:19 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1M9Frd-1oatwd12TH-006SDN; Wed, 05 Oct 2022 18:21:12 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" Subject: [PATCH v10 14/17] qemu-sockets: update socket_uri() and socket_parse() to be consistent Date: Wed, 5 Oct 2022 18:20:48 +0200 Message-Id: <20221005162051.1120041-15-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:GWWVYRFEntX6I/jSjnd2IEjmhnoeCfWWgc/s2sp+ncSRf9AxXA7 rtOW4Ceoj0to8VlYAFktx3rlhRSydqfF1ahX0LkAvCKBF6fMflpj8u2+DBT1P1V00G0Y685 tUfSS7PZK8a5cNOX8fYM+lgs7SJEJ0DlcSC4sGJ6VSl6XC5evs7tQR4zl6QA46hKl2Hp7bw +5NoiZ2TB9EN3wamSn/oQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:eesP6tPN5LU=:6CYM2mqKk6LE+83FIgiBnj CAC6yeSWZ7+Y49VQuJBkmA6utdbhSeple7Qr+kocHHEQhUHNSTjJvVl3+a0KTVOscVzS5lX0L l6/3Ddw59kWAk9YvCRQmbZceqWeikBCk9kB6L26O/UN6No63ucU6fLdSLeyc5nwUGLi9PDT1E 07HPGIyMwZaTOgTBG2PWIqsk8pqqXcnZOAXuJ3Y9pD0CBCiSy6RbS5u1KwWq0V1nvd/kEMZs4 PS/PkIyU0LqB+o+kL0QWwbrsJuRKAqXe+hzPN6KVGaSOIzJECXAbyMAN05NfonCWmU+KacUdi d8fLz3MzhAfqxS0JomlPUrbA43n8mDUm/ocBIou6stbc21N5Nw90CzYCxNT8xAUuokyyMdZ+l Y8iQ3x64kSOCeGX6zLdpgGs1lojgV/escvfMacZKZOMMZGURWyTQ7i96LGuwv5ofnyatUSFTH c3v01UWf46WpXdXl0miOEf2OToPfLBMOIJvqEKT/OJXH/T9NRKjX9p60IqQJaH7k8MMEEs7ZN 503e9AaGfW5Hsz46Nba1cCvjzejYMG+/z0vQKeepOmIj71czd+PzclQ2HBmAzELOjyB3ScW9B QPXZEFJ5Zu4KuId4Mkx40gUpp1yNpkPGT6OZ8CNoUKnSFjSvTxivm477cwr1+XCIsWEsHrG90 pZjxpqQjpqlufZqRRbC5mD+L61ta7fBAn/V4oXs6QmCArDa6tfy3IUoaQ0vccYU1nrSaRN9Ux TmAGChygRJgTy53MHDtf8VO0Nb9nKmn4qTXYeuS5tN4sLAR+ttlPasbOYwYLEEgLVJgFM/lzI /WHvkrA Received-SPF: permerror client-ip=212.227.17.24; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" To be consistent with socket_uri(), add 'tcp:' prefix for inet type in socket_parse(), by default socket_parse() use tcp when no prefix is provided (format is host:port). In socket_uri(), use 'vsock:' prefix for vsock type rather than 'tcp:' because it makes a vsock address look like an inet address with CID misinterpreted as host. Goes back to commit 9aca82ba31 "migration: Create socket-address parameter" Signed-off-by: Laurent Vivier Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Markus Armbruster Reviewed-by: David Gibson --- util/qemu-sockets.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 9f6f655fd526..a9926af714c4 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -1090,7 +1090,7 @@ char *socket_uri(SocketAddress *addr) case SOCKET_ADDRESS_TYPE_FD: return g_strdup_printf("fd:%s", addr->u.fd.str); case SOCKET_ADDRESS_TYPE_VSOCK: - return g_strdup_printf("tcp:%s:%s", + return g_strdup_printf("vsock:%s:%s", addr->u.vsock.cid, addr->u.vsock.port); default: @@ -1124,6 +1124,11 @@ SocketAddress *socket_parse(const char *str, Error **errp) if (vsock_parse(&addr->u.vsock, str + strlen("vsock:"), errp)) { goto fail; } + } else if (strstart(str, "tcp:", NULL)) { + addr->type = SOCKET_ADDRESS_TYPE_INET; + if (inet_parse(&addr->u.inet, str + strlen("tcp:"), errp)) { + goto fail; + } } else { addr->type = SOCKET_ADDRESS_TYPE_INET; if (inet_parse(&addr->u.inet, str, errp)) { From patchwork Wed Oct 5 16:20:49 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999483 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4AA0CC433F5 for ; Wed, 5 Oct 2022 16:59:11 +0000 (UTC) Received: from localhost ([::1]:56638 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7ji-0001Vh-2y for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:59:10 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46944) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og797-0007V3-DE for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:21 -0400 Received: from mout.kundenserver.de ([217.72.192.75]:43295) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og792-0002pO-DE for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:21 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MeCxd-1pELMs1H1D-00bNBF; Wed, 05 Oct 2022 18:21:13 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" Subject: [PATCH v10 15/17] net: stream: move to QIO to enable additional parameters Date: Wed, 5 Oct 2022 18:20:49 +0200 Message-Id: <20221005162051.1120041-16-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:tQs95C/6cwU3V68TJNxjS8A0MKlicb5KnEfED4/VSFLVblqhoHn 5KwP094tXimXbUeYTxCAWuVsdVmNfb0zwsGYlVJhAbVFI1C4ablTFgl8sohABpuaP9tDgAm +WL756ntqczpHqZaVoJUhvJ/90DvpQrNvO03Uu/X7MYbXF/SXCIV5c2/ykzlI1ddhc6ceWA GDN6s7pgvc/VeehROdxhg== X-UI-Out-Filterresults: notjunk:1;V03:K0:viFprx2RP/k=:QT0LyRTfjNUVuHn+bdAf2/ B+pR0c349uhjCQr994pdeqGCu3oWm9bdApHsD/zeR/L3NAvwVJ1MOLjkcDa/IXEm2Zhr3/rHx AD1R1BaLLVzOfmjVe0zB9CNujJoOAT4FL4mLE/kd7h8wDzMEGrqZ71xuF0+hoQ1fy5LG2fxbz vzNtN2l3aUGnjl/lBpifsk5jPhAm0YVw8yvk3eHcjyeiA8QcEafa8tEq5sc2+3xeG3JV4bdgP CzukSKXzKDwZL5FBnaPc1AGp+8BiW0GDcz6eyQdpxBjaKaKNh/wiB5XjsPHDYwa8pHv+wxCMf td7sjhYnsSQ55sKSeE7eGom9dZQsT+fy6WM38rGg3V3VeSJ/N5LOX150tq7K29hwbCXld6lZ/ a76UuSqsnw4OwamnAzUYOTks9/pr8W/n52N/4XzCnmdN8nr3UfrerX9wbrf7uskjWdnuuZc+k gHMuq2+/A+2uRPyNC13qedhGhR0a9UIA8HIU+kbkwZprl64IpeyRttOHm/PojVCX3RtLYq6+m oNQHaA1815DF9NPaUSeSRdKCuv5mz+ihwEbOLiqb6ky4vZGK+6KoK+eDIGgQigfOZGqL8w4dF U3HBqoyVFITuAJqcYEMdGYDkHKVI8ZVM6r039Utw1zTMRCn+MWhmJ4Tszktne0La/OjeuaG6s 9PSgTWN9KMQCR7HUBrc8d4Kxnsq8413DS2dzjCFxOxqkYWQbcU89zVZIEZBRvKwinmqOHsNTk 6tplFu5Y9iZA0rJs+SEqYtxB6nCUXcJz3G7sXiHi2YaxRqy1mSWGujRK3pTSDwGBbnsOVsH0M 1IF4lEU Received-SPF: permerror client-ip=217.72.192.75; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Use QIOChannel, QIOChannelSocket and QIONetListener. This allows net/stream to use all the available parameters provided by SocketAddress. Signed-off-by: Laurent Vivier --- net/stream.c | 484 +++++++++++++++++------------------------------- qemu-options.hx | 4 +- 2 files changed, 171 insertions(+), 317 deletions(-) diff --git a/net/stream.c b/net/stream.c index d26c79d035fc..8e4618e3f84d 100644 --- a/net/stream.c +++ b/net/stream.c @@ -35,48 +35,36 @@ #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" typedef struct NetStreamState { NetClientState nc; - int listen_fd; - int fd; + 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*/ - bool read_poll; /* waiting to receive data? */ - bool write_poll; /* waiting to transmit data? */ } NetStreamState; -static void net_stream_send(void *opaque); -static void net_stream_accept(void *opaque); -static void net_stream_writable(void *opaque); +static void net_stream_listen(QIONetListener *listener, + QIOChannelSocket *cioc, + void *opaque); -static void net_stream_update_fd_handler(NetStreamState *s) +static gboolean net_stream_writable(QIOChannel *ioc, + GIOCondition condition, + gpointer data) { - qemu_set_fd_handler(s->fd, - s->read_poll ? net_stream_send : NULL, - s->write_poll ? net_stream_writable : NULL, - s); -} - -static void net_stream_read_poll(NetStreamState *s, bool enable) -{ - s->read_poll = enable; - net_stream_update_fd_handler(s); -} - -static void net_stream_write_poll(NetStreamState *s, bool enable) -{ - s->write_poll = enable; - net_stream_update_fd_handler(s); -} - -static void net_stream_writable(void *opaque) -{ - NetStreamState *s = opaque; + NetStreamState *s = data; - net_stream_write_poll(s, false); + s->ioc_write_tag = 0; qemu_flush_queued_packets(&s->nc); + + return G_SOURCE_REMOVE; } static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf, @@ -93,13 +81,16 @@ static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf, .iov_len = size, }, }; + struct iovec local_iov[2]; + unsigned int nlocal_iov; size_t remaining; ssize_t ret; - remaining = iov_size(iov, 2) - s->send_index; - ret = iov_send(s->fd, iov, 2, s->send_index, remaining); - if (ret == -1 && errno == EAGAIN) { + remaining = iov_size(iov, 2) - s->send_index; + nlocal_iov = iov_copy(local_iov, 2, iov, 2, s->send_index, remaining); + ret = qio_channel_writev(s->ioc, local_iov, nlocal_iov, NULL); + if (ret == QIO_CHANNEL_ERR_BLOCK) { ret = 0; /* handled further down */ } if (ret == -1) { @@ -108,19 +99,25 @@ static ssize_t net_stream_receive(NetClientState *nc, const uint8_t *buf, } if (ret < (ssize_t)remaining) { s->send_index += ret; - net_stream_write_poll(s, true); + s->ioc_write_tag = qio_channel_add_watch(s->ioc, G_IO_OUT, + net_stream_writable, s, NULL); return 0; } s->send_index = 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 = DO_UPCAST(NetStreamState, nc, nc); - if (!s->read_poll) { - net_stream_read_poll(s, true); + if (!s->ioc_read_tag) { + s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, + net_stream_send, s, NULL); } } @@ -131,19 +128,24 @@ static void net_stream_rs_finalize(SocketReadState *rs) if (qemu_send_packet_async(&s->nc, rs->buf, rs->packet_len, net_stream_send_completed) == 0) { - net_stream_read_poll(s, false); + if (s->ioc_read_tag) { + g_source_remove(s->ioc_read_tag); + s->ioc_read_tag = 0; + } } } -static void net_stream_send(void *opaque) +static gboolean net_stream_send(QIOChannel *ioc, + GIOCondition condition, + gpointer data) { - NetStreamState *s = opaque; + NetStreamState *s = data; int size; int ret; - uint8_t buf1[NET_BUFSIZE]; - const uint8_t *buf; + char buf1[NET_BUFSIZE]; + const char *buf; - size = recv(s->fd, buf1, sizeof(buf1), 0); + size = qio_channel_read(s->ioc, buf1, sizeof(buf1), NULL); if (size < 0) { if (errno != EWOULDBLOCK) { goto eoc; @@ -151,51 +153,63 @@ static void net_stream_send(void *opaque) } else if (size == 0) { /* end of connection */ eoc: - net_stream_read_poll(s, false); - net_stream_write_poll(s, false); - if (s->listen_fd != -1) { - qemu_set_fd_handler(s->listen_fd, net_stream_accept, NULL, s); + s->ioc_read_tag = 0; + if (s->ioc_write_tag) { + g_source_remove(s->ioc_write_tag); + s->ioc_write_tag = 0; + } + if (s->listener) { + qio_net_listener_set_client_func(s->listener, net_stream_listen, + s, NULL); } - closesocket(s->fd); + object_unref(OBJECT(s->ioc)); + s->ioc = NULL; - s->fd = -1; net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); s->nc.link_down = true; qemu_set_info_str(&s->nc, ""); - return; + return G_SOURCE_REMOVE; } buf = buf1; - ret = net_fill_rstate(&s->rs, buf, size); + ret = net_fill_rstate(&s->rs, (const uint8_t *)buf, size); if (ret == -1) { goto eoc; } + + return G_SOURCE_CONTINUE; } static void net_stream_cleanup(NetClientState *nc) { NetStreamState *s = DO_UPCAST(NetStreamState, nc, nc); - if (s->fd != -1) { - net_stream_read_poll(s, false); - net_stream_write_poll(s, false); - close(s->fd); - s->fd = -1; + if (s->ioc) { + if (QIO_CHANNEL_SOCKET(s->ioc)->fd != -1) { + if (s->ioc_read_tag) { + g_source_remove(s->ioc_read_tag); + s->ioc_read_tag = 0; + } + if (s->ioc_write_tag) { + g_source_remove(s->ioc_write_tag); + s->ioc_write_tag = 0; + } + } + object_unref(OBJECT(s->ioc)); + s->ioc = NULL; } - if (s->listen_fd != -1) { - qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); - closesocket(s->listen_fd); - s->listen_fd = -1; + if (s->listen_ioc) { + if (s->listener) { + qio_net_listener_disconnect(s->listener); + object_unref(OBJECT(s->listener)); + s->listener = NULL; + } + object_unref(OBJECT(s->listen_ioc)); + s->listen_ioc = NULL; } } -static void net_stream_connect(void *opaque) -{ - NetStreamState *s = opaque; - net_stream_read_poll(s, true); -} - static NetClientInfo net_stream_info = { .type = NET_CLIENT_DRIVER_STREAM, .size = sizeof(NetStreamState), @@ -203,76 +217,67 @@ static NetClientInfo net_stream_info = { .cleanup = net_stream_cleanup, }; -static NetStreamState *net_stream_fd_init(NetClientState *peer, - const char *model, - const char *name, - int fd, int is_connected) +static void net_stream_listen(QIONetListener *listener, + QIOChannelSocket *cioc, + void *opaque) { - NetClientState *nc; - NetStreamState *s; + NetStreamState *s = opaque; + SocketAddress *addr; + char *uri; - nc = qemu_new_net_client(&net_stream_info, peer, model, name); + object_ref(OBJECT(cioc)); - qemu_set_info_str(nc, "fd=%d", fd); + qio_net_listener_set_client_func(s->listener, NULL, s, NULL); - s = DO_UPCAST(NetStreamState, nc, nc); + s->ioc = QIO_CHANNEL(cioc); + qio_channel_set_name(s->ioc, "stream-server"); + s->nc.link_down = false; - s->fd = fd; - s->listen_fd = -1; - net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); + s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_send, + s, NULL); - /* Disable Nagle algorithm on TCP sockets to reduce latency */ - socket_set_nodelay(fd); - - if (is_connected) { - net_stream_connect(s); + if (cioc->localAddr.ss_family == AF_UNIX) { + addr = qio_channel_socket_get_local_address(cioc, NULL); } else { - qemu_set_fd_handler(s->fd, NULL, net_stream_connect, s); + addr = qio_channel_socket_get_remote_address(cioc, NULL); } - return s; + g_assert(addr != NULL); + uri = socket_uri(addr); + qemu_set_info_str(&s->nc, uri); + g_free(uri); + qapi_free_SocketAddress(addr); + } -static void net_stream_accept(void *opaque) +static void net_stream_server_listening(QIOTask *task, gpointer opaque) { NetStreamState *s = opaque; - struct sockaddr_storage saddr; - socklen_t len; - int fd; - - for (;;) { - len = sizeof(saddr); - fd = qemu_accept(s->listen_fd, (struct sockaddr *)&saddr, &len); - if (fd < 0 && errno != EINTR) { - return; - } else if (fd >= 0) { - qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL); - break; - } - } + QIOChannelSocket *listen_sioc = QIO_CHANNEL_SOCKET(s->listen_ioc); + SocketAddress *addr; + int ret; - s->fd = fd; - s->nc.link_down = false; - net_stream_connect(s); - switch (saddr.ss_family) { - case AF_INET: { - struct sockaddr_in *saddr_in = (struct sockaddr_in *)&saddr; - - qemu_set_info_str(&s->nc, "connection from %s:%d", - inet_ntoa(saddr_in->sin_addr), - ntohs(saddr_in->sin_port)); - break; + if (listen_sioc->fd < 0) { + qemu_set_info_str(&s->nc, "connection error"); + return; } - case AF_UNIX: { - struct sockaddr_un saddr_un; - len = sizeof(saddr_un); - getsockname(s->listen_fd, (struct sockaddr *)&saddr_un, &len); - qemu_set_info_str(&s->nc, "connect from %s", saddr_un.sun_path); - break; - } - default: - g_assert_not_reached(); + addr = qio_channel_socket_get_local_address(listen_sioc, NULL); + g_assert(addr != NULL); + ret = qemu_socket_try_set_nonblock(listen_sioc->fd); + if (addr->type == 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); + return; } + g_assert(ret == 0); + qapi_free_SocketAddress(addr); + + s->nc.link_down = true; + s->listener = qio_net_listener_new(); + + net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); + qio_net_listener_set_client_func(s->listener, net_stream_listen, s, NULL); + qio_net_listener_add(s->listener, listen_sioc); } static int net_stream_server_init(NetClientState *peer, @@ -283,105 +288,54 @@ static int net_stream_server_init(NetClientState *peer, { NetClientState *nc; NetStreamState *s; - int fd, ret; + QIOChannelSocket *listen_sioc = qio_channel_socket_new(); - switch (addr->type) { - case SOCKET_ADDRESS_TYPE_INET: { - struct sockaddr_in saddr_in; + nc = qemu_new_net_client(&net_stream_info, peer, model, name); + s = DO_UPCAST(NetStreamState, nc, nc); - if (convert_host_port(&saddr_in, addr->u.inet.host, addr->u.inet.port, - errp) < 0) { - return -1; - } + s->listen_ioc = QIO_CHANNEL(listen_sioc); + qio_channel_socket_listen_async(listen_sioc, addr, 0, + net_stream_server_listening, s, + NULL, NULL); - fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - error_setg_errno(errp, errno, "can't create stream socket"); - return -1; - } - qemu_socket_set_nonblock(fd); + return 0; +} - socket_set_fast_reuse(fd); +static void net_stream_client_connected(QIOTask *task, gpointer opaque) +{ + NetStreamState *s = opaque; + QIOChannelSocket *sioc = QIO_CHANNEL_SOCKET(s->ioc); + SocketAddress *addr; + gchar *uri; + int ret; - ret = bind(fd, (struct sockaddr *)&saddr_in, sizeof(saddr_in)); - if (ret < 0) { - error_setg_errno(errp, errno, "can't bind ip=%s to socket", - inet_ntoa(saddr_in.sin_addr)); - closesocket(fd); - return -1; - } - break; + if (sioc->fd < 0) { + qemu_set_info_str(&s->nc, "connection error"); + return; } - case SOCKET_ADDRESS_TYPE_UNIX: { - struct sockaddr_un saddr_un; - - ret = unlink(addr->u.q_unix.path); - if (ret < 0 && errno != ENOENT) { - error_setg_errno(errp, errno, "failed to unlink socket %s", - addr->u.q_unix.path); - return -1; - } - saddr_un.sun_family = PF_UNIX; - ret = snprintf(saddr_un.sun_path, sizeof(saddr_un.sun_path), "%s", - addr->u.q_unix.path); - if (ret < 0 || ret >= sizeof(saddr_un.sun_path)) { - error_setg(errp, "UNIX socket path '%s' is too long", - addr->u.q_unix.path); - error_append_hint(errp, "Path must be less than %zu bytes\n", - sizeof(saddr_un.sun_path)); - return -1; - } + addr = qio_channel_socket_get_remote_address(sioc, NULL); + g_assert(addr != NULL); + uri = socket_uri(addr); + qemu_set_info_str(&s->nc, uri); + g_free(uri); - fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - error_setg_errno(errp, errno, "can't create stream socket"); - return -1; - } - qemu_socket_set_nonblock(fd); - - ret = bind(fd, (struct sockaddr *)&saddr_un, sizeof(saddr_un)); - if (ret < 0) { - error_setg_errno(errp, errno, "can't create socket with path: %s", - saddr_un.sun_path); - closesocket(fd); - return -1; - } - break; - } - case SOCKET_ADDRESS_TYPE_FD: - fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp); - if (fd == -1) { - return -1; - } - ret = qemu_socket_try_set_nonblock(fd); - if (ret < 0) { - error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", - name, fd); - return -1; - } - break; - default: - error_setg(errp, "only support inet or fd type"); - return -1; - } - - ret = listen(fd, 0); - if (ret < 0) { - error_setg_errno(errp, errno, "can't listen on socket"); - closesocket(fd); - return -1; + ret = qemu_socket_try_set_nonblock(sioc->fd); + if (addr->type == 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); + return; } + g_assert(ret == 0); + qapi_free_SocketAddress(addr); - nc = qemu_new_net_client(&net_stream_info, peer, model, name); - s = DO_UPCAST(NetStreamState, nc, nc); - s->fd = -1; - s->listen_fd = fd; - s->nc.link_down = true; net_socket_rs_init(&s->rs, net_stream_rs_finalize, false); - qemu_set_fd_handler(s->listen_fd, net_stream_accept, NULL, s); - return 0; + /* Disable Nagle algorithm on TCP sockets to reduce latency */ + qio_channel_set_delay(s->ioc, false); + + s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_send, + s, NULL); } static int net_stream_client_init(NetClientState *peer, @@ -391,118 +345,18 @@ static int net_stream_client_init(NetClientState *peer, Error **errp) { NetStreamState *s; - struct sockaddr_in saddr_in; - struct sockaddr_un saddr_un; - int fd, connected, ret; - - switch (addr->type) { - case SOCKET_ADDRESS_TYPE_INET: - if (convert_host_port(&saddr_in, addr->u.inet.host, addr->u.inet.port, - errp) < 0) { - return -1; - } + NetClientState *nc; + QIOChannelSocket *sioc = qio_channel_socket_new(); - fd = qemu_socket(PF_INET, SOCK_STREAM, 0); - if (fd < 0) { - error_setg_errno(errp, errno, "can't create stream socket"); - return -1; - } - qemu_socket_set_nonblock(fd); - - connected = 0; - for (;;) { - ret = connect(fd, (struct sockaddr *)&saddr_in, sizeof(saddr_in)); - if (ret < 0) { - if (errno == EINTR || errno == EWOULDBLOCK) { - /* continue */ - } else if (errno == EINPROGRESS || - errno == EALREADY) { - break; - } else { - error_setg_errno(errp, errno, "can't connect socket"); - closesocket(fd); - return -1; - } - } else { - connected = 1; - break; - } - } - break; - case SOCKET_ADDRESS_TYPE_UNIX: - saddr_un.sun_family = PF_UNIX; - ret = snprintf(saddr_un.sun_path, sizeof(saddr_un.sun_path), "%s", - addr->u.q_unix.path); - if (ret < 0 || ret >= sizeof(saddr_un.sun_path)) { - error_setg(errp, "UNIX socket path '%s' is too long", - addr->u.q_unix.path); - error_append_hint(errp, "Path must be less than %zu bytes\n", - sizeof(saddr_un.sun_path)); - return -1; - } + nc = qemu_new_net_client(&net_stream_info, peer, model, name); + s = DO_UPCAST(NetStreamState, nc, nc); - fd = qemu_socket(PF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - error_setg_errno(errp, errno, "can't create stream socket"); - return -1; - } - qemu_socket_set_nonblock(fd); - - connected = 0; - for (;;) { - ret = connect(fd, (struct sockaddr *)&saddr_un, sizeof(saddr_un)); - if (ret < 0) { - if (errno == EINTR || errno == EWOULDBLOCK) { - /* continue */ - } else if (errno == EAGAIN || - errno == EALREADY) { - break; - } else { - error_setg_errno(errp, errno, "can't connect socket"); - closesocket(fd); - return -1; - } - } else { - connected = 1; - break; - } - } - break; - case SOCKET_ADDRESS_TYPE_FD: - fd = monitor_fd_param(monitor_cur(), addr->u.fd.str, errp); - if (fd == -1) { - return -1; - } - ret = qemu_socket_try_set_nonblock(fd); - if (ret < 0) { - error_setg_errno(errp, -ret, "%s: Can't use file descriptor %d", - name, fd); - return -1; - } - connected = 1; - break; - default: - error_setg(errp, "only support inet, unix or fd type"); - return -1; - } + s->ioc = QIO_CHANNEL(sioc); + + qio_channel_socket_connect_async(sioc, addr, + net_stream_client_connected, s, + NULL, NULL); - s = net_stream_fd_init(peer, model, name, fd, connected); - - switch (addr->type) { - case SOCKET_ADDRESS_TYPE_INET: - qemu_set_info_str(&s->nc, "connect to %s:%d", - inet_ntoa(saddr_in.sin_addr), - ntohs(saddr_in.sin_port)); - break; - case SOCKET_ADDRESS_TYPE_UNIX: - qemu_set_info_str(&s->nc, " connect to %s", saddr_un.sun_path); - break; - case SOCKET_ADDRESS_TYPE_FD: - qemu_set_info_str(&s->nc, "connect to fd %d", fd); - break; - default: - g_assert_not_reached(); - } return 0; } diff --git a/qemu-options.hx b/qemu-options.hx index 1111e02a220c..8357ee2d96d7 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -2756,8 +2756,8 @@ DEF("netdev", HAS_ARG, QEMU_OPTION_netdev, "-netdev socket,id=str[,fd=h][,udp=host:port][,localaddr=host:port]\n" " configure a network backend to connect to another network\n" " using an UDP tunnel\n" - "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port\n" - "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path\n" + "-netdev stream,id=str[,server=on|off],addr.type=inet,addr.host=host,addr.port=port[,to=maxport][,numeric=on|off][,keep-alive=on|off][,mptcp=on|off][,addr.ipv4=on|off][,addr.ipv6=on|off]\n" + "-netdev stream,id=str[,server=on|off],addr.type=unix,addr.path=path[,abstract=on|off][,tight=on|off]\n" "-netdev stream,id=str[,server=on|off],addr.type=fd,addr.str=file-descriptor\n" " configure a network backend to connect to another network\n" " using a socket connection in stream mode.\n" From patchwork Wed Oct 5 16:20:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999482 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BE30EC433F5 for ; Wed, 5 Oct 2022 16:54:33 +0000 (UTC) Received: from localhost ([::1]:45444 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7fE-0004bY-EW for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 12:54:32 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:49448) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og79C-0007dT-SY for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:26 -0400 Received: from mout.kundenserver.de ([217.72.192.74]:43509) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og799-0002qz-46 for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:25 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1MQ5nK-1otOna3BDM-00M43W; Wed, 05 Oct 2022 18:21:15 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" Subject: [PATCH v10 16/17] tests/qtest: netdev: test stream and dgram backends Date: Wed, 5 Oct 2022 18:20:50 +0200 Message-Id: <20221005162051.1120041-17-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:iD2XF02Elofs207/BZbT/FrTr+RhUpI8/tqcJDdMEtBapIztTTN imwVTvXLkBKV4TV5+Tss057ESdW/CpvXGuK5DYkvFNnPqrJ9o8Jx3E1zDHAqFf8J9JvOjjQ 4QBSzJwfVyUUdljuQ/YkpVZq7ATvqledwyVCj0ORchGAhgy5Pvt8e0GSOsg/RujPMgpVntX /BKKBVtAYZ0nHewLRmjzA== X-UI-Out-Filterresults: notjunk:1;V03:K0:rXDB0BlxXs4=:yvxZAai+M7cSRFcj9Fcp4G OKX6YuqaIQeL0RWGE91V5C3kIl7mh6zzU6AdiRw/+QkHgDQVeK6HOOcX5CbKB6jAcLjT0IOY0 EB52GCh8q9/bqvZL9tThTqfQyg2rrFTRtiuWNPzeol19hcUMCs2S7Gdg1GpuJ/L88De4XoWRR HQipoHKi9loNNbYeZCVZnjBmb/3K8kmywSX5X9sgNdD/aHpJfUT5PDqOtTKQA8Muh7id6Q4xt lW5nwR+y3maz8rXM0GuxMq9dJ1k7/7f4ylvlWZOYxDgS8KZkrqdC05r6vHWrN8+aG9R4Hl8Fk 8IuPEaw8To7oLnSVO881I/Ak4VoIhtoQR7a2uy+98g1oKulrL7HZ7PO0oJS7vdDsbnSBkUnM3 k9ViJJBQlr99wZbhvX9pr0HW30ChXyMeFZ6/Ub2hvPheZpFtlcepo7cTnQpn/T6QbM7XmAaM8 RH01GvVDjskdPP09LAuMUxpdupRtmDEV+G3xNnuZpulmgEnQatGJ//x2O7dJmOXzZ7F2Mdwnw dxoAc1ECDTiyk6kGO+7Shom7jAHg9GuCFb3ALRIwktIog5WJgH5+zV2h3+BtCx68BILb1ZcWy TVZMukfMB/WZu0lkQQ2iPcxRn0X39wg+yOdM/YxcAsUcv2I24k83UKVfIyruIPfJ5elRfD/GR AuZDCUrNpwA+ZaP64E56Xjq4HLNJE8+M4X3NK0J7ZfBDJ+4LdfTNJDm+Xc04PfEHXPDzqkTRo t8NDuoZ8y+mOgE9zcoapGcBssQZOkHlO4Z+8TAopFnkRCteuHKRPbp4kmaUx+Qm+DGr3HBhYM zakkiNr Received-SPF: permerror client-ip=217.72.192.74; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Signed-off-by: Laurent Vivier --- tests/qtest/meson.build | 1 + tests/qtest/netdev-socket.c | 417 ++++++++++++++++++++++++++++++++++++ 2 files changed, 418 insertions(+) create mode 100644 tests/qtest/netdev-socket.c diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 455f1bbb7e52..464774e7b630 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -27,6 +27,7 @@ qtests_generic = [ 'test-hmp', 'qos-test', 'readconfig-test', + 'netdev-socket', ] if config_host.has_key('CONFIG_MODULES') qtests_generic += [ 'modules-test' ] diff --git a/tests/qtest/netdev-socket.c b/tests/qtest/netdev-socket.c new file mode 100644 index 000000000000..4ea66b4c6988 --- /dev/null +++ b/tests/qtest/netdev-socket.c @@ -0,0 +1,417 @@ +/* + * QTest testcase for netdev stream and dgram + * + * Copyright (c) 2022 Red Hat, Inc. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "libqtest.h" + +#define CONNECTION_TIMEOUT 5 + +#define EXPECT_STATE(q, e, t) \ +do { \ + char *resp = qtest_hmp(q, "info network"); \ + if (t) { \ + strrchr(resp, t)[0] = 0; \ + } \ + g_test_timer_start(); \ + while (g_test_timer_elapsed() < CONNECTION_TIMEOUT) { \ + if (strcmp(resp, e) == 0) { \ + break; \ + } \ + g_free(resp); \ + resp = qtest_hmp(q, "info network"); \ + if (t) { \ + strrchr(resp, t)[0] = 0; \ + } \ + } \ + g_assert_cmpstr(resp, ==, e); \ + g_free(resp); \ +} while (0) + +static int inet_get_free_port_socket(int sock) +{ + struct sockaddr_in addr; + socklen_t len; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = 0; + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + return -1; + } + + len = sizeof(addr); + if (getsockname(sock, (struct sockaddr *)&addr, &len) < 0) { + return -1; + } + + return ntohs(addr.sin_port); +} + +static int inet_get_free_port_multiple(int nb, int *port) +{ + int sock[nb]; + int i; + + for (i = 0; i < nb; i++) { + sock[i] = socket(AF_INET, SOCK_STREAM, 0); + if (sock[i] < 0) { + break; + } + port[i] = inet_get_free_port_socket(sock[i]); + } + + nb = i; + for (i = 0; i < nb; i++) { + closesocket(sock[i]); + } + + return nb; +} + +static int inet_get_free_port(void) +{ + int nb, port; + + nb = inet_get_free_port_multiple(1, &port); + g_assert_cmpint(nb, ==, 1); + + return port; +} + +static void test_stream_inet_ipv4(void) +{ + QTestState *qts0, *qts1; + char *expect; + int port; + + port = inet_get_free_port(); + qts0 = qtest_initf("-nodefaults " + "-netdev stream,id=st0,addr.type=inet," + "addr.ipv4=on,addr.ipv6=off," + "addr.host=localhost,addr.port=%d", port); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults " + "-netdev stream,server=false,id=st0,addr.type=inet," + "addr.ipv4=on,addr.ipv6=off," + "addr.host=localhost,addr.port=%d", port); + + expect = g_strdup_printf("st0: index=0,type=stream,tcp:127.0.0.1:%d\r\n", + port); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + /* the port is unknown, check only the address */ + EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:127.0.0.1", ':'); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_stream_inet_ipv6(void) +{ + QTestState *qts0, *qts1; + char *expect; + int port; + + port = inet_get_free_port(); + qts0 = qtest_initf("-nodefaults " + "-netdev stream,id=st0,addr.type=inet," + "addr.ipv4=off,addr.ipv6=on," + "addr.host=localhost,addr.port=%d", port); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults " + "-netdev stream,server=false,id=st0,addr.type=inet," + "addr.ipv4=off,addr.ipv6=on," + "addr.host=localhost,addr.port=%d", port); + + expect = g_strdup_printf("st0: index=0,type=stream,tcp:::1:%d\r\n", + port); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + /* the port is unknown, check only the address */ + EXPECT_STATE(qts0, "st0: index=0,type=stream,tcp:::1", ':'); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_stream_unix(void) +{ + QTestState *qts0, *qts1; + char *expect; + gchar *path; + int ret; + + ret = g_file_open_tmp("netdev-XXXXXX", &path, NULL); + g_assert_true(ret >= 0); + close(ret); + + qts0 = qtest_initf("-nodefaults " + "-netdev stream,id=st0,addr.type=unix,addr.path=%s,", + path); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults " + "-netdev stream,id=st0,server=false," + "addr.type=unix,addr.path=%s", + path); + + expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); + EXPECT_STATE(qts1, expect, 0); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + unlink(path); + g_free(path); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_stream_unix_abstract(void) +{ + QTestState *qts0, *qts1; + char *expect; + gchar *path; + int ret; + + ret = g_file_open_tmp("netdev-XXXXXX", &path, NULL); + g_assert_true(ret >= 0); + close(ret); + + qts0 = qtest_initf("-nodefaults " + "-netdev stream,id=st0,addr.type=unix,addr.path=%s," + "addr.abstract=on", + path); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + qts1 = qtest_initf("-nodefaults " + "-netdev stream,id=st0,server=false," + "addr.type=unix,addr.path=%s,addr.abstract=on", + path); + + expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); + EXPECT_STATE(qts1, expect, 0); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + unlink(path); + g_free(path); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_stream_fd(void) +{ + QTestState *qts0, *qts1; + char *expect; + int ret, sock0, sock1; + struct sockaddr_un addr; + gchar *path; + + ret = g_file_open_tmp("netdev-XXXXXX", &path, NULL); + g_assert_true(ret >= 0); + close(ret); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, path); + + unlink(addr.sun_path); + sock0 = socket(AF_LOCAL, SOCK_STREAM, 0); + g_assert_cmpint(sock0, !=, -1); + + ret = bind(sock0, (struct sockaddr *)&addr, sizeof(addr)); + g_assert_cmpint(ret, !=, -1); + + qts0 = qtest_initf("-nodefaults " + "-netdev stream,id=st0,addr.type=fd,addr.str=%d", + sock0); + + EXPECT_STATE(qts0, "st0: index=0,type=stream,\r\n", 0); + + sock1 = socket(AF_LOCAL, SOCK_STREAM, 0); + g_assert_cmpint(sock1, !=, -1); + + ret = connect(sock1, (struct sockaddr *)&addr, sizeof(addr)); + g_assert_cmpint(ret, !=, -1); + + qts1 = qtest_initf("-nodefaults " + "-netdev stream,id=st0,server=off,addr.type=fd,addr.str=%d", + sock1); + + + expect = g_strdup_printf("st0: index=0,type=stream,unix:%s\r\n", path); + EXPECT_STATE(qts1, expect, 0); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qtest_quit(qts1); + qtest_quit(qts0); + + closesocket(sock0); + closesocket(sock1); + + g_free(path); +} + +static void test_dgram_inet(void) +{ + QTestState *qts0, *qts1; + char *expect; + int port[2]; + int nb; + + nb = inet_get_free_port_multiple(2, port); + g_assert_cmpint(nb, ==, 2); + + qts0 = qtest_initf("-nodefaults " + "-netdev dgram,id=st0," + "local.type=inet,local.host=localhost,local.port=%d," + "remote.type=inet,remote.host=localhost,remote.port=%d", + port[0], port[1]); + + expect = g_strdup_printf("st0: index=0,type=dgram," + "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + port[0], port[1]); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qts1 = qtest_initf("-nodefaults " + "-netdev dgram,id=st0," + "local.type=inet,local.host=localhost,local.port=%d," + "remote.type=inet,remote.host=localhost,remote.port=%d", + port[1], port[0]); + + expect = g_strdup_printf("st0: index=0,type=dgram," + "udp=127.0.0.1:%d/127.0.0.1:%d\r\n", + port[1], port[0]); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_dgram_mcast(void) +{ + QTestState *qts; + + qts = qtest_initf("-nodefaults " + "-netdev dgram,id=st0," + "remote.type=inet,remote.host=230.0.0.1,remote.port=1234"); + + EXPECT_STATE(qts, "st0: index=0,type=dgram,mcast=230.0.0.1:1234\r\n", 0); + + qtest_quit(qts); +} + +static void test_dgram_unix(void) +{ + QTestState *qts0, *qts1; + char *expect; + gchar *path0, *path1; + int ret; + + ret = g_file_open_tmp("netdev-XXXXXX", &path0, NULL); + g_assert_true(ret >= 0); + close(ret); + + ret = g_file_open_tmp("netdev-XXXXXX", &path1, NULL); + g_assert_true(ret >= 0); + close(ret); + + qts0 = qtest_initf("-nodefaults " + "-netdev dgram,id=st0,local.type=unix,local.path=%s," + "remote.type=unix,remote.path=%s", + path0, path1); + + expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", + path0, path1); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qts1 = qtest_initf("-nodefaults " + "-netdev dgram,id=st0,local.type=unix,local.path=%s," + "remote.type=unix,remote.path=%s", + path1, path0); + + + expect = g_strdup_printf("st0: index=0,type=dgram,udp=%s:%s\r\n", + path1, path0); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + unlink(path0); + g_free(path0); + unlink(path1); + g_free(path1); + + qtest_quit(qts1); + qtest_quit(qts0); +} + +static void test_dgram_fd(void) +{ + QTestState *qts0, *qts1; + char *expect; + int ret; + int sv[2]; + + ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, sv); + g_assert_cmpint(ret, !=, -1); + + qts0 = qtest_initf("-nodefaults " + "-netdev dgram,id=st0,local.type=fd,local.str=%d", + sv[0]); + + expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[0]); + EXPECT_STATE(qts0, expect, 0); + g_free(expect); + + qts1 = qtest_initf("-nodefaults " + "-netdev dgram,id=st0,local.type=fd,local.str=%d", + sv[1]); + + + expect = g_strdup_printf("st0: index=0,type=dgram,fd=%d unix\r\n", sv[1]); + EXPECT_STATE(qts1, expect, 0); + g_free(expect); + + qtest_quit(qts1); + qtest_quit(qts0); + + closesocket(sv[0]); + closesocket(sv[1]); +} + +int main(int argc, char **argv) +{ + int ret; + + g_test_init(&argc, &argv, NULL); + + qtest_add_func("/netdev/stream/inet/ipv4", test_stream_inet_ipv4); + qtest_add_func("/netdev/stream/inet/ipv6", test_stream_inet_ipv6); + qtest_add_func("/netdev/stream/unix", test_stream_unix); + qtest_add_func("/netdev/stream/unix/abstract", test_stream_unix_abstract); + qtest_add_func("/netdev/stream/fd", test_stream_fd); + qtest_add_func("/netdev/dgram/inet", test_dgram_inet); + qtest_add_func("/netdev/dgram/mcast", test_dgram_mcast); + qtest_add_func("/netdev/dgram/unix", test_dgram_unix); + qtest_add_func("/netdev/dgram/fd", test_dgram_fd); + + ret = g_test_run(); + + return ret; +} From patchwork Wed Oct 5 16:20:51 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12999486 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 0C99BC433F5 for ; Wed, 5 Oct 2022 17:06:04 +0000 (UTC) Received: from localhost ([::1]:35486 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1og7qM-00019h-5M for qemu-devel@archiver.kernel.org; Wed, 05 Oct 2022 13:06:02 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:46942) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og797-0007U3-0s for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:21 -0400 Received: from mout.kundenserver.de ([217.72.192.73]:33129) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1og795-0002pw-0l for qemu-devel@nongnu.org; Wed, 05 Oct 2022 12:21:20 -0400 Received: from lenovo-t14s.redhat.com ([82.142.8.70]) by mrelayeu.kundenserver.de (mreue109 [212.227.15.183]) with ESMTPSA (Nemesis) id 1N336J-1pKQ9G44CL-013JLj; Wed, 05 Oct 2022 18:21:16 +0200 From: Laurent Vivier To: qemu-devel@nongnu.org Cc: Thomas Huth , =?utf-8?q?Daniel_P=2E_Berrang=C3=A9?= , Eric Blake , "Dr. David Alan Gilbert" , David Gibson , Jason Wang , Samuel Thibault , Markus Armbruster , Paolo Bonzini , Stefan Weil , Greg Kurz , Laurent Vivier , "Michael S. Tsirkin" Subject: [PATCH v10 17/17] net: stream: add QAPI events to report connection state Date: Wed, 5 Oct 2022 18:20:51 +0200 Message-Id: <20221005162051.1120041-18-lvivier@redhat.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20221005162051.1120041-1-lvivier@redhat.com> References: <20221005162051.1120041-1-lvivier@redhat.com> MIME-Version: 1.0 X-Provags-ID: V03:K1:FeeVUmUVqZAXA9vnWy09Ptp2DcaGUWfqZVV0nkmUM/fsVbz4FlP MV3gOqBiZsV07uDMlp0Eb2+Fw/Ldv4Mk6dYG9AEOHD7wKPu0M4KCN5v789VT8Y9o8sJlhHY VrrergbI5Ql5ewo6LvJ2LKLyaPmxRwTc8Hus8AFzUHpTiaR+R6S9RqHCjHN/jXpSj5tQl77 QTLd5E1QlrW+eUo7hFKfA== X-UI-Out-Filterresults: notjunk:1;V03:K0:3Mt3iotd5WY=:oKKoJR4CFw6QXT19Oi59zE Q63JgRPN7V5jIohJ74WpzgxhXHq23K2LqqRbnuOC6EleKf/0C7yPDco6adDmhB4yxaamGlWRl BstbaN4a5cdxcsmxaOPAu6QfJ07KfwU6Z2fB6Ai+fQzNCJxDi72A7x795CCCMhcXjhFLRlxAq PZ5Q+DzKc5C2+C1LyxAiAI4fDDbEo5w4TU4c1bzIeSQwGPvB/z6dFdoji69PsrvSVMWM0MtqM w4Lj32oZUQK4KHm8xYtro/mQqE5B1y/YQMtrZ4B2swR2FAy6SJ2gg/Qb6Cjhjz1s0WYiXX52I bs3H2xwzdGhMb170x4Y9lHqw5Im+E8FxejhYy/vpKAL97XLjYyb6Puo20sA7LWtLX/fiY0yu6 6zz0dYOqLp2hEs+1daiRYl8D/1tWEu8fXnlk+168I/3CVTkgQ+box6hwhWaIQJgGlesXM6533 q31ODpIiALpZBKNByCzLp3edZh1Y+r1G7gBeDKrVrtEWxtDukMRng0F/pFQRuU3tk8BG3jbB7 EV83IahpNxNOxwbCyRV4sXoBJaSBwF9tBpTt7lrwhsxLHY9n0AC6z7rv1RAMcl3qugmZKb8ud 2iYuFs1CU7zSdohG9eCp/9gZzNkROWGBp2P7Mp1wZS78rNP/1AuvaycjL2Ys0q16L0L2151c+ nxBu9gsWS1Fa+1TnFwusK19UNhz3Y6ENY0GZi1yKeOnkhl3BHyoqLUZEsaCdmQy5VQV9WTThN tzdoKUbwmfzpI0w6LZqc8QX72OTz+/9bj9/5jxZX3eMKMZl0Oz/zyY5B4HOpPKgKaTAK0wv8q aeFUW9M Received-SPF: permerror client-ip=217.72.192.73; envelope-from=lvivier@redhat.com; helo=mout.kundenserver.de X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_FAIL=0.001, SPF_HELO_NONE=0.001 autolearn=no 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+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" The netdev reports NETDEV_STREAM_CONNECTED event when the backend is connected, and NETDEV_STREAM_EOC when it is disconnected. The NETDEV_STREAM_CONNECTED event includes the URI of the destination address. Signed-off-by: Laurent Vivier --- net/stream.c | 11 +++++++++-- qapi/net.json | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/net/stream.c b/net/stream.c index 8e4618e3f84d..926c6e6a015e 100644 --- a/net/stream.c +++ b/net/stream.c @@ -38,6 +38,7 @@ #include "io/channel.h" #include "io/channel-socket.h" #include "io/net-listener.h" +#include "qapi/qapi-events-net.h" typedef struct NetStreamState { NetClientState nc; @@ -169,6 +170,8 @@ static gboolean net_stream_send(QIOChannel *ioc, s->nc.link_down = true; qemu_set_info_str(&s->nc, ""); + qapi_event_send_netdev_stream_eoc(s->nc.name); + return G_SOURCE_REMOVE; } buf = buf1; @@ -244,9 +247,10 @@ static void net_stream_listen(QIONetListener *listener, g_assert(addr != NULL); uri = socket_uri(addr); qemu_set_info_str(&s->nc, uri); - g_free(uri); qapi_free_SocketAddress(addr); + qapi_event_send_netdev_stream_connected(s->nc.name, uri); + g_free(uri); } static void net_stream_server_listening(QIOTask *task, gpointer opaque) @@ -318,12 +322,12 @@ static void net_stream_client_connected(QIOTask *task, gpointer opaque) g_assert(addr != NULL); uri = socket_uri(addr); qemu_set_info_str(&s->nc, uri); - g_free(uri); ret = qemu_socket_try_set_nonblock(sioc->fd); if (addr->type == 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); + g_free(uri); return; } g_assert(ret == 0); @@ -336,6 +340,9 @@ static void net_stream_client_connected(QIOTask *task, gpointer opaque) s->ioc_read_tag = qio_channel_add_watch(s->ioc, G_IO_IN, net_stream_send, s, NULL); + + qapi_event_send_netdev_stream_connected(s->nc.name, uri); + g_free(uri); } static int net_stream_client_init(NetClientState *peer, diff --git a/qapi/net.json b/qapi/net.json index 14d1531536c5..3173682b4e09 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -891,3 +891,49 @@ ## { 'event': 'FAILOVER_NEGOTIATED', 'data': {'device-id': 'str'} } + +## +# @NETDEV_STREAM_CONNECTED: +# +# Emitted when the netdev stream backend is connected +# +# @netdev-id: QEMU netdev id that is connected +# @uri: The Uniform Resource Identifier identifying the destination address +# +# Since: 7.2 +# +# Example: +# +# <- { 'event': 'NETDEV_STREAM_CONNECTED', +# 'data': {'uri': 'tcp:::1:1234', 'netdev-id': 'netdev0'}, +# 'timestamp': {'seconds': 1663330564, 'microseconds': 804317} } +# +# or +# +# <- { 'event': 'NETDEV_STREAM_CONNECTED', +# 'data': {'uri': ''unix:/tmp/qemu0', 'netdev-id': 'netdev0'}, +# 'timestamp': {'seconds': 1663330564, 'microseconds': 804317} } +# +## +{ 'event': 'NETDEV_STREAM_CONNECTED', + 'data': { 'netdev-id': 'str', + 'uri': 'str' } } + +## +# @NETDEV_STREAM_EOC: +# +# Emitted when the netdev stream backend is disconnected +# +# @netdev-id: QEMU netdev id that is disconnected +# +# Since: 7.2 +# +# Example: +# +# <- { 'event': 'NETDEV_STREAM_EOC', +# 'data': {'netdev-id': 'netdev0'}, +# 'timestamp': {'seconds': 1663330937, 'microseconds': 526695} } +# +## +{ 'event': 'NETDEV_STREAM_EOC', + 'data': { 'netdev-id': 'str' } }