From nobody Sat Feb 7 15:10:49 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 207.211.31.120 as permitted sender) client-ip=207.211.31.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 207.211.31.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=1578652494; cv=none; d=zohomail.com; s=zohoarc; b=es4LLgLvjotdmx/1tF7hjyvx0VtVslZYcbPeBJUdt3Nv7kqab1bJVPz2UgrwtG8JUENIs4wsEaGT3FWqfnM0ooVRc07ud6uHAkPoHN1KMA4YK1TLzaL9h+loQb24Suf6Iqx9G3QyXItFp3c4CpUcJPyLruakXzQqrsQGU482oj8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1578652494; 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=JOH0f/bg4XR78U3XkV/YlvbaNgF6bZ90GQmrKF9Uvcw=; b=YMvA8O/pim2wXtt7gdBzOlTgicpMEVWiBIC9ZxQbuqsds18iLAfXwf7kDMTuppnAZefLQfVDRzD68a1qqBK6xnIswx9PsBw+ix3Z/7wCO7Y+0uKfl2rTO+PlRGpMS0usGDkb+hhq9W964gXGlzlEj/lsF0ChIiYJe7Aeli5AjCY= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 207.211.31.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 [207.211.31.120]) by mx.zohomail.com with SMTPS id 1578652494356942.123915322187; Fri, 10 Jan 2020 02:34:54 -0800 (PST) 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-53-YOGUfuB0NX-ObStwIQ9CIQ-1; Fri, 10 Jan 2020 05:34:51 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id E25EC800EBF; Fri, 10 Jan 2020 10:34:45 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id BCC3E5C28C; Fri, 10 Jan 2020 10:34:45 +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 78335503D4; Fri, 10 Jan 2020 10:34:45 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 00AAYfa0001931 for ; Fri, 10 Jan 2020 05:34:41 -0500 Received: by smtp.corp.redhat.com (Postfix) id 5DFF986CA0; Fri, 10 Jan 2020 10:34:41 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-112-65.ams2.redhat.com [10.36.112.65]) by smtp.corp.redhat.com (Postfix) with ESMTP id 87DDF84665; Fri, 10 Jan 2020 10:34:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1578652493; 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=JOH0f/bg4XR78U3XkV/YlvbaNgF6bZ90GQmrKF9Uvcw=; b=P6GYmEnNTT1IjCi591pPBHCiNdQWpUUFgfKby8Fk9cAvJyOCZ+S01fRP0amDszypNikuc0 fCSQKgOU9f4ghBSfKXoI0j/GeAPesbTUo64TCvl+6yDkmHTdAJSYuYrKaxkhkNO4ZZ3O3d Dt21Us6JGq170m/nZuyJhWpiu0qYtMQ= From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Date: Fri, 10 Jan 2020 10:34:28 +0000 Message-Id: <20200110103430.3564679-5-berrange@redhat.com> In-Reply-To: <20200110103430.3564679-1-berrange@redhat.com> References: <20200110103430.3564679-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v4 4/6] qemu: add support for running QEMU driver in embedded mode 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.16 X-MC-Unique: YOGUfuB0NX-ObStwIQ9CIQ-1 X-Mimecast-Spam-Score: 0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) This enables support for running QEMU embedded to the calling application process using a URI: qemu:///embed?root=3D/some/path Note that it is important to keep the path reasonably short to avoid risk of hitting the limit on UNIX socket path names which is 108 characters. When using the embedded mode with a root=3D/var/tmp/embed, the driver will use the following paths: logDir: /var/tmp/embed/log/qemu swtpmLogDir: /var/tmp/embed/log/swtpm configBaseDir: /var/tmp/embed/etc/qemu stateDir: /var/tmp/embed/run/qemu swtpmStateDir: /var/tmp/embed/run/swtpm cacheDir: /var/tmp/embed/cache/qemu libDir: /var/tmp/embed/lib/qemu swtpmStorageDir: /var/tmp/embed/lib/swtpm defaultTLSx509certdir: /var/tmp/embed/etc/pki/qemu These are identical whether the embedded driver is privileged or unprivileged. This compares with the system instance which uses logDir: /var/log/libvirt/qemu swtpmLogDir: /var/log/swtpm/libvirt/qemu configBaseDir: /etc/libvirt/qemu stateDir: /run/libvirt/qemu swtpmStateDir: /run/libvirt/qemu/swtpm cacheDir: /var/cache/libvirt/qemu libDir: /var/lib/libvirt/qemu swtpmStorageDir: /var/lib/libvirt/swtpm defaultTLSx509certdir: /etc/pki/qemu At this time all features present in the QEMU driver are available when running in embedded mode, availability matching whether the embedded driver is privileged or unprivileged. Signed-off-by: Daniel P. Berrang=C3=A9 --- docs/drvqemu.html.in | 99 +++++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_conf.c | 45 +++++++++++++++++-- src/qemu/qemu_conf.h | 8 ++-- src/qemu/qemu_driver.c | 39 +++++++++++----- src/qemu/qemu_process.c | 15 +++++-- tests/domaincapstest.c | 2 +- tests/testutilsqemu.c | 3 +- 7 files changed, 186 insertions(+), 25 deletions(-) diff --git a/docs/drvqemu.html.in b/docs/drvqemu.html.in index 8beb28655c..f6abb45706 100644 --- a/docs/drvqemu.html.in +++ b/docs/drvqemu.html.in @@ -63,6 +63,105 @@ qemu+tcp://example.com/system (remote access, SA= Sl/Kerberos) qemu+ssh://root@example.com/system (remote access, SSH tunnelled) =20 +

Embedded driver

+ +

+ Since 6.0.0 the QEMU driver has experimental support for operating + in an embedded mode. In this scenario, rather than connecting to + the libvirtd daemon, the QEMU driver runs in the client application + process directly. To use this the client application must have + registered & be running an instance of the event loop. To open + the driver in embedded mode the app use the new URI path and specify + a virtual root directory under which the driver will create content. +

+ +
+      qemu:///embed?root=3D/some/dir
+    
+ +

+ Broadly speaking the range of functionality is intended to be + on a par with that seen when using the traditional system or + session libvirt connections to QEMU. The features will of course + differ depending on whether the application using the embedded + driver is running privileged or unprivileged. For example PCI + device assignment or TAP based networking are only available + when running privileged. While the embedded mode is still classed + as experimental some features may change their default settings + between releases. +

+ +

+ By default if the application uses any APIs associated with + secondary drivers, these will result in a connection being + opened to the corresponding driver in libvirtd. For example, + this allows a virtual machine from the embedded QEMU to connect + its NIC to a virtual network or connect its disk to a storage + volume. Some of the secondary drivers will also be able to support + running in embedded mode. Currently this is supported by the + secrets driver, to allow for use of VMs with encrypted disks +

+ +

Directory tree

+ +

+ Under the specified root directory the following locations will + be used +

+ +
+/some/dir
+  |
+  +- log
+  |   |
+  |   +- qemu
+  |   +- swtpm
+  |
+  +- etc
+  |   |
+  |   +- qemu
+  |   +- pki
+  |       |
+  |       +- qemu
+  |
+  +- run
+  |   |
+  |   +- qemu
+  |   +- swtpm
+  |
+  +- cache
+  |   |
+  |   +- qemu
+  |
+  +- lib
+      |
+      +- qemu
+      +- swtpm
+    
+ +

+ Note that UNIX domain sockets used for QEMU virtual machines had + a maximum filename length of 108 characters. Bear this in mind + when picking a root directory to avoid risk of exhausting the + filename space. The application is responsible for recursively + purging the contents of this directory tree once they no longer + require a connection, though it can also be left intact for reuse + when opening a future connection. +

+ +

API usage with event loop>

+ +

+ To use the QEMU driver in embedded mode the application must + register an event loop with libvirt. Many of the QEMU driver + API calls will rely on the event loop processing data. With this + in mind, applications must NEVER invoke API + calls from the event loop thread itself, only other threads. + Not following this rule will lead to deadlocks in the API. + This restriction is intended to be lifted in a future release + of libvirt, once QMP processing moves to a dedicated thread. +

+

Driver security architecture

=20

diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index b62dd1df52..fc42c2820e 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -104,7 +104,8 @@ qemuDriverUnlock(virQEMUDriverPtr driver) #endif =20 =20 -virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged) +virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged, + const char *root) { g_autoptr(virQEMUDriverConfig) cfg =3D NULL; =20 @@ -114,7 +115,11 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool pri= vileged) if (!(cfg =3D virObjectNew(virQEMUDriverConfigClass))) return NULL; =20 - cfg->uri =3D privileged ? "qemu:///system" : "qemu:///session"; + if (root) { + cfg->uri =3D g_strdup_printf("qemu:///embed?root=3D%s", root); + } else { + cfg->uri =3D g_strdup(privileged ? "qemu:///system" : "qemu:///ses= sion"); + } =20 if (privileged) { if (virGetUserID(QEMU_USER, &cfg->user) < 0) @@ -130,7 +135,24 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool pri= vileged) =20 cfg->cgroupControllers =3D -1; /* -1 =3D=3D auto-detect */ =20 - if (privileged) { + if (root !=3D NULL) { + cfg->logDir =3D g_strdup_printf("%s/log/qemu", root); + cfg->swtpmLogDir =3D g_strdup_printf("%s/log/swtpm", root); + cfg->configBaseDir =3D g_strdup_printf("%s/etc", root); + cfg->stateDir =3D g_strdup_printf("%s/run/qemu", root); + cfg->swtpmStateDir =3D g_strdup_printf("%s/run/swtpm", root); + cfg->cacheDir =3D g_strdup_printf("%s/cache/qemu", root); + cfg->libDir =3D g_strdup_printf("%s/lib/qemu", root); + cfg->swtpmStorageDir =3D g_strdup_printf("%s/lib/swtpm", root); + + cfg->saveDir =3D g_strdup_printf("%s/save", cfg->libDir); + cfg->snapshotDir =3D g_strdup_printf("%s/snapshot", cfg->libDir); + cfg->checkpointDir =3D g_strdup_printf("%s/checkpoint", cfg->libDi= r); + cfg->autoDumpPath =3D g_strdup_printf("%s/dump", cfg->libDir); + cfg->channelTargetDir =3D g_strdup_printf("%s/channel/target", cfg= ->libDir); + cfg->nvramDir =3D g_strdup_printf("%s/nvram", cfg->libDir); + cfg->memoryBackingDir =3D g_strdup_printf("%s/ram", cfg->libDir); + } else if (privileged) { cfg->logDir =3D g_strdup_printf("%s/log/libvirt/qemu", LOCALSTATED= IR); =20 cfg->swtpmLogDir =3D g_strdup_printf("%s/log/swtpm/libvirt/qemu", @@ -189,6 +211,16 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool pri= vileged) cfg->memoryBackingDir =3D g_strdup_printf("%s/qemu/ram", cfg->conf= igBaseDir); cfg->swtpmStorageDir =3D g_strdup_printf("%s/qemu/swtpm", cfg->configBaseDir); + } + + if (privileged) { + if (!virDoesUserExist("tss") || + virGetUserID("tss", &cfg->swtpm_user) < 0) + cfg->swtpm_user =3D 0; /* fall back to root */ + if (!virDoesGroupExist("tss") || + virGetGroupID("tss", &cfg->swtpm_group) < 0) + cfg->swtpm_group =3D 0; /* fall back to root */ + } else { cfg->swtpm_user =3D (uid_t)-1; cfg->swtpm_group =3D (gid_t)-1; } @@ -201,7 +233,11 @@ virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool pri= vileged) * This will then be used as a fallback if the service specific * directory doesn't exist (although we don't check if this exists). */ - cfg->defaultTLSx509certdir =3D g_strdup(SYSCONFDIR "/pki/qemu"); + if (root =3D=3D NULL) { + cfg->defaultTLSx509certdir =3D g_strdup(SYSCONFDIR "pki/qemu"); + } else { + cfg->defaultTLSx509certdir =3D g_strdup_printf("%s/etc/pki/qemu", = root); + } =20 cfg->vncListen =3D g_strdup(VIR_LOOPBACK_IPV4_ADDR); cfg->spiceListen =3D g_strdup(VIR_LOOPBACK_IPV4_ADDR); @@ -264,6 +300,7 @@ static void virQEMUDriverConfigDispose(void *obj) virBitmapFree(cfg->namespaces); =20 virStringListFree(cfg->cgroupDeviceACL); + VIR_FREE(cfg->uri); =20 VIR_FREE(cfg->configBaseDir); VIR_FREE(cfg->configDir); diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index b9401635d7..4ab1999568 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -75,7 +75,7 @@ typedef virQEMUDriverConfig *virQEMUDriverConfigPtr; struct _virQEMUDriverConfig { virObject parent; =20 - const char *uri; + char *uri; =20 uid_t user; gid_t group; @@ -240,8 +240,9 @@ struct _virQEMUDriver { /* Atomic inc/dec only */ unsigned int nactive; =20 - /* Immutable value */ + /* Immutable values */ bool privileged; + char *embeddedRoot; =20 /* Immutable pointers. Caller must provide locking */ virStateInhibitCallback inhibitCallback; @@ -313,7 +314,8 @@ struct _virQEMUDriver { virHashAtomicPtr migrationErrors; }; =20 -virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged); +virQEMUDriverConfigPtr virQEMUDriverConfigNew(bool privileged, + const char *root); =20 int virQEMUDriverConfigLoadFile(virQEMUDriverConfigPtr cfg, const char *filename, diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 56d420f608..5088a1573c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -645,12 +645,6 @@ qemuStateInitialize(bool privileged, const char *defsecmodel =3D NULL; g_autofree virSecurityManagerPtr *sec_managers =3D NULL; =20 - if (root !=3D NULL) { - virReportError(VIR_ERR_INVALID_ARG, "%s", - _("Driver does not support embedded mode")); - return -1; - } - if (VIR_ALLOC(qemu_driver) < 0) return VIR_DRV_STATE_INIT_ERROR; =20 @@ -668,6 +662,8 @@ qemuStateInitialize(bool privileged, =20 qemu_driver->privileged =3D privileged; qemu_driver->hostarch =3D virArchFromHost(); + if (root !=3D NULL) + qemu_driver->embeddedRoot =3D g_strdup(root); =20 if (!(qemu_driver->domains =3D virDomainObjListNew())) goto error; @@ -681,7 +677,7 @@ qemuStateInitialize(bool privileged, if (privileged) qemu_driver->hostsysinfo =3D virSysinfoRead(); =20 - if (!(qemu_driver->config =3D cfg =3D virQEMUDriverConfigNew(privilege= d))) + if (!(qemu_driver->config =3D cfg =3D virQEMUDriverConfigNew(privilege= d, root))) goto error; =20 if (!(driverConf =3D g_strdup_printf("%s/qemu.conf", cfg->configBaseDi= r))) @@ -1185,10 +1181,30 @@ static virDrvOpenStatus qemuConnectOpen(virConnectP= tr conn, return VIR_DRV_OPEN_ERROR; } =20 - if (!virConnectValidateURIPath(conn->uri->path, - "qemu", - virQEMUDriverIsPrivileged(qemu_driver))) - return VIR_DRV_OPEN_ERROR; + if (qemu_driver->embeddedRoot) { + const char *root =3D virURIGetParam(conn->uri, "root"); + if (!root) + return VIR_DRV_OPEN_ERROR; + + if (STRNEQ(conn->uri->path, "/embed")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("URI must be qemu:///embed")); + return VIR_DRV_OPEN_ERROR; + } + + if (STRNEQ(root, qemu_driver->embeddedRoot)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Cannot open embedded driver at path '%s', " + "already open with path '%s'"), + root, qemu_driver->embeddedRoot); + return VIR_DRV_OPEN_ERROR; + } + } else { + if (!virConnectValidateURIPath(conn->uri->path, + "qemu", + virQEMUDriverIsPrivileged(qemu_driv= er))) + return VIR_DRV_OPEN_ERROR; + } =20 if (virConnectOpenEnsureACL(conn) < 0) return VIR_DRV_OPEN_ERROR; @@ -23239,6 +23255,7 @@ static virHypervisorDriver qemuHypervisorDriver =3D= { static virConnectDriver qemuConnectDriver =3D { .localOnly =3D true, .uriSchemes =3D (const char *[]){ "qemu", NULL }, + .embeddable =3D true, .hypervisorDriver =3D &qemuHypervisorDriver, }; =20 diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 4195042194..1374f2fbc6 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -6682,10 +6682,17 @@ qemuProcessLaunch(virConnectPtr conn, =20 cfg =3D virQEMUDriverGetConfig(driver); =20 - if ((flags & VIR_QEMU_PROCESS_START_AUTODESTROY) && !conn) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Domain autodestroy requires a connection handle"= )); - return -1; + if (flags & VIR_QEMU_PROCESS_START_AUTODESTROY) { + if (!conn) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Domain autodestroy requires a connection han= dle")); + return -1; + } + if (driver->embeddedRoot) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Domain autodestroy not supported for embedde= d drivers yet")); + return -1; + } } =20 hookData.vm =3D vm; diff --git a/tests/domaincapstest.c b/tests/domaincapstest.c index 9f5eab3230..fb803eaa47 100644 --- a/tests/domaincapstest.c +++ b/tests/domaincapstest.c @@ -369,7 +369,7 @@ mymain(void) #endif =20 #if WITH_QEMU - virQEMUDriverConfigPtr cfg =3D virQEMUDriverConfigNew(false); + virQEMUDriverConfigPtr cfg =3D virQEMUDriverConfigNew(false, ""); =20 if (!cfg) return EXIT_FAILURE; diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 9db0cb44c6..39544c548f 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -380,8 +380,7 @@ int qemuTestDriverInit(virQEMUDriver *driver) return -1; =20 driver->hostarch =3D virArchFromHost(); - - driver->config =3D virQEMUDriverConfigNew(false); + driver->config =3D virQEMUDriverConfigNew(false, ""); if (!driver->config) goto error; =20 --=20 2.23.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list