<div dir="ltr"><div>I had a first version on gitlab <a href="https://gitlab.com/libvirt/libvirt/-/merge_requests/216">https://gitlab.com/libvirt/libvirt/-/merge_requests/216</a></div><div>where I added the attribute to the source. Peter Krempa noted that</div><div>this most likely has to be moved to the reconnect element.</div><div>I actually prefer adding it to reconnect (with choice in the schema).</div><div>If there are no objections I will make the necessary change...<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, 21 Feb 2023 at 23:10, Jonathon Jongsma <<a href="mailto:jjongsma@redhat.com">jjongsma@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 2/17/23 10:50 AM, Christian Nautze wrote:<br>
> Currently it's only possible to set this parameter during domain<br>
> creation via QEMU commandline passthrough feature.<br>
> With the new delay attribute it's also possible to set this<br>
> parameter if you want to attach a new NBD disk<br>
> using "virsh attach-device domain device.xml" e.g.:<br>
> <br>
> <disk type='network' device='disk'><br>
> <driver name='qemu' type='raw'/><br>
> <source protocol='nbd' name='foo'><br>
> <host name='<a href="http://example.org" rel="noreferrer" target="_blank">example.org</a>' port='6000'/><br>
> <reconnect delay='10'/><br>
> </source><br>
> <target dev='vdb' bus='virtio'/><br>
> </disk><br>
> <br>
> Signed-off-by: Christian Nautze <<a href="mailto:christian.nautze@exoscale.ch" target="_blank">christian.nautze@exoscale.ch</a>><br>
> <br>
<br>
<br>
I wonder about the choice between using an attribute vs a child element <br>
for this value. Most of the things that use child elements for are more <br>
complex values. For example, 'host' is an address and a port, 'cookies' <br>
is a collection of cookie elements, even the existing 'reconnect' <br>
element has two sub-values. On the other hand, things that are a simple <br>
value tend to be specified as attributes instead. NBD sources in <br>
particular have attributes 'name', 'tls', and 'tlsHostname'. Since this <br>
is a single integer value, I wonder if it would make more sense to use <br>
another nbd-specific attribute such as 'reconnectDelay'. For example:<br>
<br>
<source protocol='nbd' name='foo' reconnectDelay='10'><br>
<br>
This might also reduce potential confusion about how to specify the <br>
'reconnect' element, but has the downside of having two different <br>
reconnect-related elements. To be honest, I'm not sure whether there is <br>
an overal philosophy on attributes vs. elements, so I will happily defer <br>
to more veteran libvirt developers.<br>
<br>
If we do use the <reconnect> sub-element, I think the schema would need <br>
to use <choice> to indicate that it's either ('enabled'+'timeout') OR <br>
'delay', not an arbitrary subset of these attributes.<br>
<br>
Jonathon<br>
<br>
<br>
> ---<br>
> Change: reconnect element: drop mandatory 'enabled' attribute when using 'delay'<br>
> ---<br>
> docs/formatdomain.rst | 11 +++++++--<br>
> src/conf/domain_conf.c | 12 ++++++++++<br>
> src/conf/schemas/domaincommon.rng | 3 +++<br>
> src/conf/schemas/storagecommon.rng | 13 ++++++++---<br>
> src/conf/storage_source_conf.c | 1 +<br>
> src/conf/storage_source_conf.h | 4 ++++<br>
> src/qemu/qemu_block.c | 4 +++-<br>
> src/qemu/qemu_domain.c | 9 ++++++++<br>
> .../disk-network-nbd.x86_64-latest.args | 23 +++++++++++--------<br>
> tests/qemuxml2argvdata/disk-network-nbd.xml | 8 +++++++<br>
> tests/qemuxml2xmloutdata/disk-network-nbd.xml | 9 ++++++++<br>
> 11 files changed, 81 insertions(+), 16 deletions(-)<br>
> <br>
> diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst<br>
> index 36c6d87907..ee30c51cea 100644<br>
> --- a/docs/formatdomain.rst<br>
> +++ b/docs/formatdomain.rst<br>
> @@ -2946,13 +2946,20 @@ paravirtualized driver is specified via the ``disk`` element.<br>
> are intended to be default, then the entire element may be omitted.<br>
> ``reconnect``<br>
> For disk type ``vhostuser`` configures reconnect timeout if the connection<br>
> - is lost. It has two mandatory attributes:<br>
> + is lost. This is set with the two mandatory attributes ``enabled`` and<br>
> + ``timeout``.<br>
> + For disk type ``network`` and protocol ``nbd`` the QEMU NBD reconnect delay<br>
> + can be set via attribute ``delay``:<br>
> <br>
> ``enabled``<br>
> If the reconnect feature is enabled, accepts ``yes`` and ``no``<br>
> ``timeout``<br>
> The amount of seconds after which hypervisor tries to reconnect.<br>
> -<br>
> + ``delay``<br>
> + Only for NBD hosts. The amount of seconds during which all requests are<br>
> + paused and will be rerun after a successful reconnect. After that time, any<br>
> + delayed requests and all future requests before a successful reconnect<br>
> + will immediately fail. If not set the default QEMU value is 0.<br>
> <br>
> For a "file" or "volume" disk type which represents a cdrom or floppy (the<br>
> ``device`` attribute), it is possible to define policy what to do with the<br>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c<br>
> index a5578324b9..3f2ba2aab8 100644<br>
> --- a/src/conf/domain_conf.c<br>
> +++ b/src/conf/domain_conf.c<br>
> @@ -7146,6 +7146,15 @@ virDomainDiskSourceNetworkParse(xmlNodePtr node,<br>
> src->tlsFromConfig = !!value;<br>
> }<br>
> <br>
> + if (src->protocol == VIR_STORAGE_NET_PROTOCOL_NBD) {<br>
> + xmlNodePtr cur;<br>
> + if ((cur = virXPathNode("./reconnect", ctxt))) {<br>
> + if (virXMLPropUInt(cur, "delay", 10, VIR_XML_PROP_NONE,<br>
> + &src->reconnectDelay) < 0)<br>
> + return -1;<br>
> + }<br>
> + }<br>
> +<br>
> /* for historical reasons we store the volume and image name in one XML<br>
> * element although it complicates thing when attempting to access them. */<br>
> if (src->path &&<br>
> @@ -22073,6 +22082,9 @@ virDomainDiskSourceFormatNetwork(virBuffer *attrBuf,<br>
> virBufferAddLit(childBuf, "/>\n");<br>
> }<br>
> <br>
> + if (src->reconnectDelay) {<br>
> + virBufferAsprintf(childBuf, "<reconnect delay='%u'/>\n", src->reconnectDelay);<br>
> + }<br>
> <br>
> virBufferEscapeString(childBuf, "<snapshot name='%s'/>\n", src->snapshot);<br>
> virBufferEscapeString(childBuf, "<config file='%s'/>\n", src->configFile);<br>
> diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng<br>
> index a57dd212ab..dd5fbeac09 100644<br>
> --- a/src/conf/schemas/domaincommon.rng<br>
> +++ b/src/conf/schemas/domaincommon.rng<br>
> @@ -2199,6 +2199,9 @@<br>
> </optional><br>
> <ref name="diskSourceCommon"/><br>
> <ref name="diskSourceNetworkHost"/><br>
> + <optional><br>
> + <ref name="reconnect"/><br>
> + </optional><br>
> <optional><br>
> <ref name="encryption"/><br>
> </optional><br>
> diff --git a/src/conf/schemas/storagecommon.rng b/src/conf/schemas/storagecommon.rng<br>
> index 4d6e646c9a..582375358c 100644<br>
> --- a/src/conf/schemas/storagecommon.rng<br>
> +++ b/src/conf/schemas/storagecommon.rng<br>
> @@ -55,14 +55,21 @@<br>
> <br>
> <define name="reconnect"><br>
> <element name="reconnect"><br>
> - <attribute name="enabled"><br>
> - <ref name="virYesNo"/><br>
> - </attribute><br>
> + <optional><br>
> + <attribute name="enabled"><br>
> + <ref name="virYesNo"/><br>
> + </attribute><br>
> + </optional><br>
> <optional><br>
> <attribute name="timeout"><br>
> <ref name="unsignedInt"/><br>
> </attribute><br>
> </optional><br>
> + <optional><br>
> + <attribute name="delay"><br>
> + <ref name="unsignedInt"/><br>
> + </attribute><br>
> + </optional><br>
> </element><br>
> </define><br>
> <br>
> diff --git a/src/conf/storage_source_conf.c b/src/conf/storage_source_conf.c<br>
> index cecd7e811e..58009fd06e 100644<br>
> --- a/src/conf/storage_source_conf.c<br>
> +++ b/src/conf/storage_source_conf.c<br>
> @@ -811,6 +811,7 @@ virStorageSourceCopy(const virStorageSource *src,<br>
> def->sslverify = src->sslverify;<br>
> def->readahead = src->readahead;<br>
> def->timeout = src->timeout;<br>
> + def->reconnectDelay = src->reconnectDelay;<br>
> def->metadataCacheMaxSize = src->metadataCacheMaxSize;<br>
> <br>
> /* storage driver metadata are not copied */<br>
> diff --git a/src/conf/storage_source_conf.h b/src/conf/storage_source_conf.h<br>
> index 14a6825d54..c6187dda59 100644<br>
> --- a/src/conf/storage_source_conf.h<br>
> +++ b/src/conf/storage_source_conf.h<br>
> @@ -312,6 +312,10 @@ struct _virStorageSource {<br>
> unsigned long long readahead; /* size of the readahead buffer in bytes */<br>
> unsigned long long timeout; /* connection timeout in seconds */<br>
> <br>
> + /* NBD QEMU reconnect-delay option,<br>
> + * 0 as default value */<br>
> + unsigned int reconnectDelay;<br>
> +<br>
> virStorageSourceNVMeDef *nvme; /* type == VIR_STORAGE_TYPE_NVME */<br>
> <br>
> virDomainChrSourceDef *vhostuser; /* type == VIR_STORAGE_TYPE_VHOST_USER */<br>
> diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c<br>
> index 5e700eff99..8fcebd8992 100644<br>
> --- a/src/qemu/qemu_block.c<br>
> +++ b/src/qemu/qemu_block.c<br>
> @@ -529,6 +529,7 @@ qemuBlockStorageSourceGetNBDProps(virStorageSource *src,<br>
> "S:export", src->path,<br>
> "S:tls-creds", tlsAlias,<br>
> "S:tls-hostname", tlsHostname,<br>
> + "p:reconnect-delay", src->reconnectDelay,<br>
> NULL) < 0)<br>
> return NULL;<br>
> <br>
> @@ -1848,7 +1849,8 @@ qemuBlockGetBackingStoreString(virStorageSource *src,<br>
> src->ncookies == 0 &&<br>
> src->sslverify == VIR_TRISTATE_BOOL_ABSENT &&<br>
> src->timeout == 0 &&<br>
> - src->readahead == 0) {<br>
> + src->readahead == 0 &&<br>
> + src->reconnectDelay == 0) {<br>
> <br>
> switch ((virStorageNetProtocol) src->protocol) {<br>
> case VIR_STORAGE_NET_PROTOCOL_NBD:<br>
> diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c<br>
> index e9bc0f375d..02ae3823fb 100644<br>
> --- a/src/qemu/qemu_domain.c<br>
> +++ b/src/qemu/qemu_domain.c<br>
> @@ -5020,6 +5020,15 @@ qemuDomainValidateStorageSource(virStorageSource *src,<br>
> }<br>
> }<br>
> <br>
> + if (src->reconnectDelay > 0) {<br>
> + if (actualType != VIR_STORAGE_TYPE_NETWORK ||<br>
> + src->protocol != VIR_STORAGE_NET_PROTOCOL_NBD) {<br>
> + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",<br>
> + _("reconnect delay is supported only with NBD protocol"));<br>
> + return -1;<br>
> + }<br>
> + }<br>
> +<br>
> if (src->query &&<br>
> (actualType != VIR_STORAGE_TYPE_NETWORK ||<br>
> (src->protocol != VIR_STORAGE_NET_PROTOCOL_HTTPS &&<br>
> diff --git a/tests/qemuxml2argvdata/disk-network-nbd.x86_64-latest.args b/tests/qemuxml2argvdata/disk-network-nbd.x86_64-latest.args<br>
> index 21e619af3e..e8d13b0bd4 100644<br>
> --- a/tests/qemuxml2argvdata/disk-network-nbd.x86_64-latest.args<br>
> +++ b/tests/qemuxml2argvdata/disk-network-nbd.x86_64-latest.args<br>
> @@ -28,21 +28,24 @@ XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \<br>
> -no-acpi \<br>
> -boot strict=on \<br>
> -device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0x2"}' \<br>
> --blockdev '{"driver":"nbd","server":{"type":"inet","host":"<a href="http://example.org" rel="noreferrer" target="_blank">example.org</a>","port":"6000"},"node-name":"libvirt-5-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> +-blockdev '{"driver":"nbd","server":{"type":"inet","host":"<a href="http://example.org" rel="noreferrer" target="_blank">example.org</a>","port":"6000"},"node-name":"libvirt-6-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> +-blockdev '{"node-name":"libvirt-6-format","read-only":false,"driver":"raw","file":"libvirt-6-storage"}' \<br>
> +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x2","drive":"libvirt-6-format","id":"virtio-disk0","bootindex":1}' \<br>
> +-blockdev '{"driver":"nbd","server":{"type":"inet","host":"<a href="http://example.org" rel="noreferrer" target="_blank">example.org</a>","port":"6000"},"export":"bar","node-name":"libvirt-5-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> -blockdev '{"node-name":"libvirt-5-format","read-only":false,"driver":"raw","file":"libvirt-5-storage"}' \<br>
> --device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x2","drive":"libvirt-5-format","id":"virtio-disk0","bootindex":1}' \<br>
> --blockdev '{"driver":"nbd","server":{"type":"inet","host":"<a href="http://example.org" rel="noreferrer" target="_blank">example.org</a>","port":"6000"},"export":"bar","node-name":"libvirt-4-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x3","drive":"libvirt-5-format","id":"virtio-disk1"}' \<br>
> +-blockdev '{"driver":"nbd","server":{"type":"inet","host":"::1","port":"6000"},"node-name":"libvirt-4-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> -blockdev '{"node-name":"libvirt-4-format","read-only":false,"driver":"raw","file":"libvirt-4-storage"}' \<br>
> --device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x3","drive":"libvirt-4-format","id":"virtio-disk1"}' \<br>
> --blockdev '{"driver":"nbd","server":{"type":"inet","host":"::1","port":"6000"},"node-name":"libvirt-3-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x4","drive":"libvirt-4-format","id":"virtio-disk2"}' \<br>
> +-blockdev '{"driver":"nbd","server":{"type":"inet","host":"::1","port":"6000"},"export":"bar","node-name":"libvirt-3-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> -blockdev '{"node-name":"libvirt-3-format","read-only":false,"driver":"raw","file":"libvirt-3-storage"}' \<br>
> --device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x4","drive":"libvirt-3-format","id":"virtio-disk2"}' \<br>
> --blockdev '{"driver":"nbd","server":{"type":"inet","host":"::1","port":"6000"},"export":"bar","node-name":"libvirt-2-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x5","drive":"libvirt-3-format","id":"virtio-disk3"}' \<br>
> +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/var/run/nbdsock"},"export":"bar","node-name":"libvirt-2-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> -blockdev '{"node-name":"libvirt-2-format","read-only":false,"driver":"raw","file":"libvirt-2-storage"}' \<br>
> --device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x5","drive":"libvirt-2-format","id":"virtio-disk3"}' \<br>
> --blockdev '{"driver":"nbd","server":{"type":"unix","path":"/var/run/nbdsock"},"export":"bar","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x6","drive":"libvirt-2-format","id":"virtio-disk4"}' \<br>
> +-blockdev '{"driver":"nbd","server":{"type":"inet","host":"<a href="http://example.org" rel="noreferrer" target="_blank">example.org</a>","port":"6000"},"export":"foo","reconnect-delay":10,"node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unmap"}' \<br>
> -blockdev '{"node-name":"libvirt-1-format","read-only":false,"driver":"raw","file":"libvirt-1-storage"}' \<br>
> --device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x6","drive":"libvirt-1-format","id":"virtio-disk4"}' \<br>
> +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x7","drive":"libvirt-1-format","id":"virtio-disk5"}' \<br>
> -audiodev '{"id":"audio1","driver":"none"}' \<br>
> -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \<br>
> -msg timestamp=on<br>
> diff --git a/tests/qemuxml2argvdata/disk-network-nbd.xml b/tests/qemuxml2argvdata/disk-network-nbd.xml<br>
> index 8ac6cc3b7b..4e8b1e5b03 100644<br>
> --- a/tests/qemuxml2argvdata/disk-network-nbd.xml<br>
> +++ b/tests/qemuxml2argvdata/disk-network-nbd.xml<br>
> @@ -49,6 +49,14 @@<br>
> </source><br>
> <target dev='vde' bus='virtio'/><br>
> </disk><br>
> + <disk type='network' device='disk'><br>
> + <driver name='qemu' type='raw'/><br>
> + <source protocol='nbd' name='foo'><br>
> + <host name='<a href="http://example.org" rel="noreferrer" target="_blank">example.org</a>' port='6000'/><br>
> + <reconnect delay='10'/><br>
> + </source><br>
> + <target dev='vdf' bus='virtio'/><br>
> + </disk><br>
> <controller type='usb' index='0'/><br>
> <controller type='ide' index='0'/><br>
> <controller type='pci' index='0' model='pci-root'/><br>
> diff --git a/tests/qemuxml2xmloutdata/disk-network-nbd.xml b/tests/qemuxml2xmloutdata/disk-network-nbd.xml<br>
> index f8dcca4bab..38d1f290c8 100644<br>
> --- a/tests/qemuxml2xmloutdata/disk-network-nbd.xml<br>
> +++ b/tests/qemuxml2xmloutdata/disk-network-nbd.xml<br>
> @@ -54,6 +54,15 @@<br>
> <target dev='vde' bus='virtio'/><br>
> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/><br>
> </disk><br>
> + <disk type='network' device='disk'><br>
> + <driver name='qemu' type='raw'/><br>
> + <source protocol='nbd' name='foo'><br>
> + <host name='<a href="http://example.org" rel="noreferrer" target="_blank">example.org</a>' port='6000'/><br>
> + <reconnect delay='10'/><br>
> + </source><br>
> + <target dev='vdf' bus='virtio'/><br>
> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/><br>
> + </disk><br>
> <controller type='usb' index='0'><br>
> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/><br>
> </controller><br>
<br>
</blockquote></div>