backup: Add support for passing server socket file descriptor to backup NBD server

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 <pkrempa@redhat.com>
Spellchecked-by: Ján Tomko <jtomko@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Peter Krempa
2025-04-01 16:18:30 +02:00
parent 2e014dfae6
commit eb768a556d
4 changed files with 56 additions and 1 deletions
+21
View File
@@ -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``.
+2 -1
View File
@@ -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);
+6
View File
@@ -90,6 +90,12 @@
<ref name="absFilePath"/>
</attribute>
</group>
<group>
<attribute name="transport">
<value>fd</value>
</attribute>
<attribute name="fdgroup"/>
</group>
</choice>
</element>
<ref name="backupDisksPull"/>
+27
View File
@@ -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;