From nobody Mon Feb 9 03:14:07 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) client-ip=205.139.110.120; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-1.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1589556569; cv=none; d=zohomail.com; s=zohoarc; b=eCGbgduxgHOhMh4lDtc7X3vdjAMbwhDsueL1NhlByt/Wd0Fg8e6I3s0Ff4Cg0VAMkL6f3wVkwMLhoyMpjKAMslmSeI5TR2WqNHtz9vkz8601hREle8Foxmn1+xKGrkBkWUXeIcv/mLaKrd+lgkZNwthjtI2Jnz+hfNfjX3ssNTM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1589556569; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=T7XV6Wu+jHKrquorpWTjqEuO1wbQZ9S8RAI3QNGXgxw=; b=ETktP9pdt91u4DX6OnUG8xdy94yo5X8lEMwLvErhZOMLoEBc6hPDuWHvOVZp/aEzvJivbjHaHG0ZREd4E9nxGxCGLw+abobJlnNc5jzVqNj/jW0fQ0qRpzNXuBDeSef9u+txF/XqEDM2h3E/7ktBbEF8DAIDWR4/jSnl95AN6JY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 205.139.110.120 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) by mx.zohomail.com with SMTPS id 1589556569491393.6488846471701; Fri, 15 May 2020 08:29:29 -0700 (PDT) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-324-Svpka2IBOimGT8SxbDCNgg-1; Fri, 15 May 2020 11:29:25 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id C2756835BC2; Fri, 15 May 2020 15:29:19 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id A2C4763BAD; Fri, 15 May 2020 15:29:19 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 6CB6B1806B0B; Fri, 15 May 2020 15:29:19 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 04FFTHYe011386 for ; Fri, 15 May 2020 11:29:17 -0400 Received: by smtp.corp.redhat.com (Postfix) id C247C5D9F5; Fri, 15 May 2020 15:29:17 +0000 (UTC) Received: from localhost.localdomain.com (unknown [10.40.208.20]) by smtp.corp.redhat.com (Postfix) with ESMTP id 385125D9D7 for ; Fri, 15 May 2020 15:29:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1589556568; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=T7XV6Wu+jHKrquorpWTjqEuO1wbQZ9S8RAI3QNGXgxw=; b=BSqT6IQc2rEB6sDJw7J/9R4f7S3Q/xwaBLHQsVK1GY9XsOwfU16u7M5s9G8UaenfGHUgka ktQ8YmOjpWOShesMc2iiyCv3zkXxdTeLQj4CDD8ysRDDvYWxqTFVr82USCU9pwmI89W0te vqTA/FGutidNNmWVPd0yMiUAEDSjWI4= X-MC-Unique: Svpka2IBOimGT8SxbDCNgg-1 From: Peter Krempa To: libvir-list@redhat.com Subject: [PATCH 14/21] qemu: command: Generate -netdev command line via JSON->cmdline conversion Date: Fri, 15 May 2020 17:28:00 +0200 Message-Id: <94e6ce557a3c6d1d2d808720cddfcacb63652d70.1589556042.git.pkrempa@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" The 'netdev_add' command was recently formally described in qemu via the QMP schema. This means that it also requires the arguments to be properly formatted. Our current approach is to generate the command line and then use qemuMonitorJSONKeywordStringToJSON to get the JSON properties for the monitor. This will not work if we need to pass some fields as numbers or booleans. In this step we re-do internals of qemuBuildHostNetStr to format a JSON object which is converted back via virQEMUBuildNetdevCommandlineFromJSON to the equivalent command line. This will later allow fixing of the monitor code to use the JSON object directly rather than rely on the conversion. Signed-off-by: Peter Krempa Reviewed-by: Eric Blake --- src/qemu/qemu_command.c | 163 +++++++++++++++++++++++++--------------- src/qemu/qemu_command.h | 12 +-- src/qemu/qemu_hotplug.c | 13 +++- 3 files changed, 119 insertions(+), 69 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 2850953bd0..00d1b4121d 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3564,7 +3564,7 @@ qemuBuildNicDevStr(virDomainDefPtr def, } -char * +virJSONValuePtr qemuBuildHostNetStr(virDomainNetDefPtr net, char **tapfd, size_t tapfdSize, @@ -3573,10 +3573,11 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, const char *slirpfd) { bool is_tap =3D false; - g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; virDomainNetType netType =3D virDomainNetGetActualType(net); size_t i; + g_autoptr(virJSONValue) netprops =3D NULL; + if (net->script && netType !=3D VIR_DOMAIN_NET_TYPE_ETHERNET) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("scripts are not supported on interfaces of type = %s"), @@ -3594,54 +3595,75 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, case VIR_DOMAIN_NET_TYPE_NETWORK: case VIR_DOMAIN_NET_TYPE_DIRECT: case VIR_DOMAIN_NET_TYPE_ETHERNET: - virBufferAddLit(&buf, "tap,"); + if (virJSONValueObjectCreate(&netprops, "s:type", "tap", NULL) < 0) + return NULL; + /* for one tapfd 'fd=3D' shall be used, * for more than one 'fds=3D' is the right choice */ if (tapfdSize =3D=3D 1) { - virBufferAsprintf(&buf, "fd=3D%s,", tapfd[0]); + if (virJSONValueObjectAdd(netprops, "s:fd", tapfd[0], NULL) < = 0) + return NULL; } else { - virBufferAddLit(&buf, "fds=3D"); - for (i =3D 0; i < tapfdSize; i++) { - if (i) - virBufferAddChar(&buf, ':'); - virBufferAdd(&buf, tapfd[i], -1); - } - virBufferAddChar(&buf, ','); + g_auto(virBuffer) fdsbuf =3D VIR_BUFFER_INITIALIZER; + + for (i =3D 0; i < tapfdSize; i++) + virBufferAsprintf(&fdsbuf, "%s:", tapfd[i]); + + virBufferTrim(&fdsbuf, ":"); + + if (virJSONValueObjectAdd(netprops, + "s:fds", virBufferCurrentContent(&fd= sbuf), + NULL) < 0) + return NULL; } + is_tap =3D true; break; case VIR_DOMAIN_NET_TYPE_CLIENT: - virBufferAsprintf(&buf, "socket,connect=3D%s:%d,", - net->data.socket.address, - net->data.socket.port); + if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) = < 0 || + virJSONValueObjectAppendStringPrintf(netprops, "connect", "%s:= %d", + net->data.socket.address, + net->data.socket.port) < = 0) + return NULL; break; case VIR_DOMAIN_NET_TYPE_SERVER: - virBufferAsprintf(&buf, "socket,listen=3D%s:%d,", - NULLSTR_EMPTY(net->data.socket.address), - net->data.socket.port); + if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) = < 0 || + virJSONValueObjectAppendStringPrintf(netprops, "listen", "%s:%= d", + NULLSTR_EMPTY(net->data.s= ocket.address), + net->data.socket.port) < = 0) + return NULL; break; case VIR_DOMAIN_NET_TYPE_MCAST: - virBufferAsprintf(&buf, "socket,mcast=3D%s:%d,", - net->data.socket.address, - net->data.socket.port); + if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) = < 0 || + virJSONValueObjectAppendStringPrintf(netprops, "mcast", "%s:%d= ", + net->data.socket.address, + net->data.socket.port) < = 0) + return NULL; break; case VIR_DOMAIN_NET_TYPE_UDP: - virBufferAsprintf(&buf, "socket,udp=3D%s:%d,localaddr=3D%s:%d,", - net->data.socket.address, - net->data.socket.port, - net->data.socket.localaddr, - net->data.socket.localport); + if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NULL) = < 0 || + virJSONValueObjectAppendStringPrintf(netprops, "udp", "%s:%d", + net->data.socket.address, + net->data.socket.port) < = 0 || + virJSONValueObjectAppendStringPrintf(netprops, "localaddr", "%= s:%d", + net->data.socket.localadd= r, + net->data.socket.localpor= t) < 0) + return NULL; break; case VIR_DOMAIN_NET_TYPE_USER: if (slirpfd) { - virBufferAsprintf(&buf, "socket,fd=3D%s,", slirpfd); + if (virJSONValueObjectCreate(&netprops, "s:type", "socket", NU= LL) < 0 || + virJSONValueObjectAppendString(netprops, "fd", slirpfd) < = 0) + return NULL; } else { - virBufferAddLit(&buf, "user,"); + if (virJSONValueObjectCreate(&netprops, "s:type", "user", NULL= ) < 0) + return NULL; + for (i =3D 0; i < net->guestIP.nips; i++) { const virNetDevIPAddr *ip =3D net->guestIP.ips[i]; g_autofree char *addr =3D NULL; @@ -3650,29 +3672,40 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, return NULL; if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET)) { - virBufferAsprintf(&buf, "net=3D%s", addr); + g_autofree char *ipv4netaddr =3D NULL; + if (ip->prefix) - virBufferAsprintf(&buf, "/%u", ip->prefix); - virBufferAddChar(&buf, ','); + ipv4netaddr =3D g_strdup_printf("%s/%u", addr, ip-= >prefix); + else + ipv4netaddr =3D g_strdup(addr); + + if (virJSONValueObjectAppendString(netprops, "net", ip= v4netaddr) < 0) + return NULL; } else if (VIR_SOCKET_ADDR_IS_FAMILY(&ip->address, AF_INET= 6)) { - virBufferAsprintf(&buf, "ipv6-prefix=3D%s,", addr); - if (ip->prefix) - virBufferAsprintf(&buf, "ipv6-prefixlen=3D%u,", ip= ->prefix); + if (virJSONValueObjectAppendString(netprops, "ipv6-pre= fix", addr) < 0) + return NULL; + if (ip->prefix && + virJSONValueObjectAppendNumberUlong(netprops, "ipv= 6-prefixlen", + ip->prefix) < = 0) + return NULL; } } } break; case VIR_DOMAIN_NET_TYPE_INTERNAL: - virBufferAddLit(&buf, "user,"); + if (virJSONValueObjectCreate(&netprops, "s:type", "user", NULL) < = 0) + return NULL; break; case VIR_DOMAIN_NET_TYPE_VHOSTUSER: - virBufferAsprintf(&buf, "vhost-user,chardev=3Dchar%s,", - net->info.alias); - if (net->driver.virtio.queues > 1) - virBufferAsprintf(&buf, "queues=3D%u,", - net->driver.virtio.queues); + if (virJSONValueObjectCreate(&netprops, "s:type", "vhost-user", NU= LL) < 0 || + virJSONValueObjectAppendStringPrintf(netprops, "chardev", "cha= r%s", net->info.alias) < 0) + return NULL; + + if (net->driver.virtio.queues > 1 && + virJSONValueObjectAppendNumberUlong(netprops, "queues", net->d= river.virtio.queues) < 0) + return NULL; break; case VIR_DOMAIN_NET_TYPE_HOSTDEV: @@ -3681,31 +3714,38 @@ qemuBuildHostNetStr(virDomainNetDefPtr net, break; } - virBufferAsprintf(&buf, "id=3Dhost%s,", net->info.alias); + if (virJSONValueObjectAppendStringPrintf(netprops, "id", "host%s", net= ->info.alias) < 0) + return NULL; if (is_tap) { if (vhostfdSize) { - virBufferAddLit(&buf, "vhost=3Don,"); + if (virJSONValueObjectAppendBoolean(netprops, "vhost", true) <= 0) + return NULL; + if (vhostfdSize =3D=3D 1) { - virBufferAsprintf(&buf, "vhostfd=3D%s,", vhostfd[0]); + if (virJSONValueObjectAdd(netprops, "s:vhostfd", vhostfd[0= ], NULL) < 0) + return NULL; } else { - virBufferAddLit(&buf, "vhostfds=3D"); - for (i =3D 0; i < vhostfdSize; i++) { - if (i) - virBufferAddChar(&buf, ':'); - virBufferAdd(&buf, vhostfd[i], -1); - } - virBufferAddChar(&buf, ','); + g_auto(virBuffer) fdsbuf =3D VIR_BUFFER_INITIALIZER; + + for (i =3D 0; i < vhostfdSize; i++) + virBufferAsprintf(&fdsbuf, "%s:", vhostfd[i]); + + virBufferTrim(&fdsbuf, ":"); + + if (virJSONValueObjectAdd(netprops, + "s:vhostfds", virBufferCurrentCo= ntent(&fdsbuf), + NULL) < 0) + return NULL; } } - if (net->tune.sndbuf_specified) - virBufferAsprintf(&buf, "sndbuf=3D%lu,", net->tune.sndbuf); - } - - virBufferTrim(&buf, ","); + if (net->tune.sndbuf_specified && + virJSONValueObjectAppendNumberUlong(netprops, "sndbuf", net->t= une.sndbuf) < 0) + return NULL; + } - return virBufferContentAndReset(&buf); + return g_steal_pointer(&netprops); } @@ -7670,6 +7710,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driver, bool requireNicdev =3D false; qemuSlirpPtr slirp; size_t i; + g_autoptr(virJSONValue) hostnetprops =3D NULL; if (!bootindex) @@ -7873,11 +7914,15 @@ qemuBuildInterfaceCommandLine(virQEMUDriverPtr driv= er, if (chardev) virCommandAddArgList(cmd, "-chardev", chardev, NULL); - if (!(host =3D qemuBuildHostNetStr(net, - tapfdName, tapfdSize, - vhostfdName, vhostfdSize, - slirpfdName))) + if (!(hostnetprops =3D qemuBuildHostNetStr(net, + tapfdName, tapfdSize, + vhostfdName, vhostfdSize, + slirpfdName))) goto cleanup; + + if (!(host =3D virQEMUBuildNetdevCommandlineFromJSON(hostnetprops))) + goto cleanup; + virCommandAddArgList(cmd, "-netdev", host, NULL); /* Possible combinations: diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 7665b68548..6cdd9debe0 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -89,12 +89,12 @@ qemuBuildChrDeviceStr(char **deviceStr, char * qemuBuildChannelGuestfwdNetdevProps(virDomainChrDefPtr chr); -char *qemuBuildHostNetStr(virDomainNetDefPtr net, - char **tapfd, - size_t tapfdSize, - char **vhostfd, - size_t vhostfdSize, - const char *slirpfd); +virJSONValuePtr qemuBuildHostNetStr(virDomainNetDefPtr net, + char **tapfd, + size_t tapfdSize, + char **vhostfd, + size_t vhostfdSize, + const char *slirpfd); /* Current, best practice */ char *qemuBuildNicDevStr(virDomainDefPtr def, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 2976ba7647..c6789dcef3 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -54,6 +54,7 @@ #include "virstoragefile.h" #include "virstring.h" #include "virtime.h" +#include "virqemu.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -1157,6 +1158,7 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, size_t vhostfdSize =3D 0; size_t queueSize =3D 0; g_autofree char *nicstr =3D NULL; + g_autoptr(virJSONValue) netprops =3D NULL; g_autofree char *netstr =3D NULL; int ret =3D -1; bool releaseaddr =3D false; @@ -1382,10 +1384,13 @@ qemuDomainAttachNetDevice(virQEMUDriverPtr driver, for (i =3D 0; i < vhostfdSize; i++) vhostfdName[i] =3D g_strdup_printf("vhostfd-%s%zu", net->info.alia= s, i); - if (!(netstr =3D qemuBuildHostNetStr(net, - tapfdName, tapfdSize, - vhostfdName, vhostfdSize, - slirpfdName))) + if (!(netprops =3D qemuBuildHostNetStr(net, + tapfdName, tapfdSize, + vhostfdName, vhostfdSize, + slirpfdName))) + goto cleanup; + + if (!(netstr =3D virQEMUBuildNetdevCommandlineFromJSON(netprops))) goto cleanup; qemuDomainObjEnterMonitor(driver, vm); --=20 2.26.2