From eb768a556db75040f7b518d198a18bd0f5d6faad Mon Sep 17 00:00:00 2001 From: Peter Krempa Date: Tue, 25 Mar 2025 17:46:45 +0100 Subject: [PATCH] backup: Add support for passing server socket file descriptor to backup NBD server MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit In deployments where libvirt is containerized together with the VM it may be hard for the management application to access listening sockets inside the container from the outside. This patch implements "transport='fd'" for the NBD server definition for backups which allows to use the existing "virDomainFDAssociate()" to pass FD to a pre-opened server socket to qemu instead of trying to create it by qemu. Add schema, enable the parser, add formatter and implement the actual passing for the qemu backup code. Signed-off-by: Peter Krempa Spellchecked-by: Ján Tomko Reviewed-by: Ján Tomko --- docs/formatbackup.rst | 21 +++++++++++++++++++++ src/conf/backup_conf.c | 3 ++- src/conf/schemas/domainbackup.rng | 6 ++++++ src/qemu/qemu_backup.c | 27 +++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/docs/formatbackup.rst b/docs/formatbackup.rst index 02847fd5d4..155a45a22f 100644 --- a/docs/formatbackup.rst +++ b/docs/formatbackup.rst @@ -1,3 +1,5 @@ + .. role:: since + Backup XML format ================= @@ -42,6 +44,25 @@ were supplied). The following child elements and attributes are supported: necessary to set up an NBD server that exposes the content of each disk at the time the backup is started. + In addition to the above the NBD server used for backups allows using + ``transport='fd' fdgroup='NAME'`` where ``NAME`` is the name used with + ``virDomainFDAssociate()`` to pass a pre-opened server socket file descriptor + to qemu. :since:`Since 11.3.0` + + Example code to pass a socket with libvirt-python bindings:: + + import socket + import libvirt + + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.bind("/path/to/socket") + + fdlist = [ s.fileno() ] + + conn = libvirt.open() + dom = conn.lookupByName("VMNAME") + dom.FDAssociate("NAME", fdlist) + Note that for the QEMU hypervisor the TLS environment in controlled using ``backup_tls_x509_cert_dir``, ``backup_tls_x509_verify``, and ``backup_tls_x509_secret_uuid`` properties in ``/etc/libvirt/qemu.conf``. diff --git a/src/conf/backup_conf.c b/src/conf/backup_conf.c index 1bdfbfa3d6..b20292af3d 100644 --- a/src/conf/backup_conf.c +++ b/src/conf/backup_conf.c @@ -228,7 +228,7 @@ virDomainBackupDefParseXML(xmlXPathContextPtr ctxt, def->server = g_new0(virStorageNetHostDef, 1); - if (virDomainStorageNetworkParseHost(node, def->server, false) < 0) + if (virDomainStorageNetworkParseHost(node, def->server, true) < 0) return NULL; if (def->server->transport == VIR_STORAGE_NET_HOST_TRANS_RDMA) { @@ -388,6 +388,7 @@ virDomainBackupDefFormat(virBuffer *buf, if (def->server->port) virBufferAsprintf(&serverAttrBuf, " port='%u'", def->server->port); virBufferEscapeString(&serverAttrBuf, " socket='%s'", def->server->socket); + virBufferEscapeString(&serverAttrBuf, " fdgroup='%s'", def->server->fdgroup); } virXMLFormatElement(&childBuf, "server", &serverAttrBuf, NULL); diff --git a/src/conf/schemas/domainbackup.rng b/src/conf/schemas/domainbackup.rng index 80ba155aad..91cf2a7bbd 100644 --- a/src/conf/schemas/domainbackup.rng +++ b/src/conf/schemas/domainbackup.rng @@ -90,6 +90,12 @@ + + + fd + + + diff --git a/src/qemu/qemu_backup.c b/src/qemu/qemu_backup.c index 2935153cdf..f6ee31dc2a 100644 --- a/src/qemu/qemu_backup.c +++ b/src/qemu/qemu_backup.c @@ -761,6 +761,7 @@ qemuBackupBegin(virDomainObj *vm, bool reuse = (flags & VIR_DOMAIN_BACKUP_BEGIN_REUSE_EXTERNAL); int rc = 0; int ret = -1; + g_autoptr(qemuFDPassDirect) fdpass = NULL; virCheckFlags(VIR_DOMAIN_BACKUP_BEGIN_REUSE_EXTERNAL, -1); @@ -847,6 +848,29 @@ qemuBackupBegin(virDomainObj *vm, priv->backup = g_steal_pointer(&def); + if (pull && priv->backup->server->fdgroup) { + virStorageSourceFDTuple *fdt = NULL; + VIR_AUTOCLOSE fdcopy = -1; + + if (!(fdt = virHashLookup(priv->fds, priv->backup->server->fdgroup))) { + virReportError(VIR_ERR_INVALID_ARG, + _("file descriptor group '%1$s' was not associated with the domain"), + priv->backup->server->fdgroup); + goto endjob; + } + + if (fdt->nfds != 1) { + virReportError(VIR_ERR_INVALID_ARG, + _("file descriptor group '%1$s' must contain only 1 file descriptor for NBD server"), + priv->backup->server->fdgroup); + goto endjob; + } + + priv->backup->server->qemu_fdname = g_strdup("libvirt-backup-nbd"); + fdcopy = dup(fdt->fds[0]); + fdpass = qemuFDPassDirectNew(priv->backup->server->qemu_fdname, &fdcopy); + } + if (qemuDomainObjEnterMonitorAsync(vm, VIR_ASYNC_JOB_BACKUP) < 0) goto endjob; @@ -857,6 +881,9 @@ qemuBackupBegin(virDomainObj *vm, if (rc == 0 && tlsProps) rc = qemuMonitorAddObject(priv->mon, &tlsProps, &tlsAlias); + if (rc == 0 && fdpass) + rc = qemuFDPassDirectTransferMonitor(fdpass, priv->mon); + if (rc == 0) { if ((rc = qemuMonitorNBDServerStart(priv->mon, priv->backup->server, tlsAlias)) == 0) nbd_running = true; -- 2.47.2