Commit Graph

47515 Commits

Author SHA1 Message Date
Laine Stump a8ee7ae301 conf: parse/format passt-related XML additions
This implements XML config to represent a subset of the features
supported by 'passt' (https://passt.top), which is an alternative
backend for emulated network devices that requires no elevated
privileges (similar to slirp, but "better").

Along with setting the backend to use passt (via <backend
type='passt'/> when the interface type='user'), we also support
passt's --log-file and --interface options (via the <backend>
subelement logFile and upstream attributes) and its --tcp-ports and
--udp-ports options (which selectively forward incoming connections to
the host on to the guest) via the new <portForward> subelement of
<interface>. Here is an example of the config for a network interface
that uses passt to connect:

    <interface type='user'>
      <mac address='52:54:00:a8:33:fc'/>
      <ip address='192.168.221.122' family='ipv4'/>
      <model type='virtio'/>
      <backend type='passt' logFile='/tmp/xyzzy.log' upstream='eth0'/>
      <portForward address='10.0.0.1' proto='tcp' dev='eth0'>
        <range start='2022' to='22'/>
        <range start='5000' end='5099' to='1000'/>
        <range start='5010' end='5029' exclude='yes'/>
      </portForward>
      <portForward proto='udp'>
        <range start='10101'/>
      </portForward>
    </interface>

In this case:

* the guest will be offered address 192.168.221.122 for its interface
  via DHCP

* the passt process will write all log messages to /tmp/xyzzy.log

* routes to the outside for the guest will be derived from the
  addresses and routes associated with the host interface "eth0".

* incoming tcp port 2022 to the host will be forwarded to port 22
  on the guest.

* incoming tcp ports 5000-5099 (with the exception of ports 5010-5029)
  to the host will be forwarded to port 1000-1099 on the guest.

* incoming udp packets on port 10101 will be forwarded (unchanged) to
  the guest.

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2023-01-09 14:24:27 -05:00
Laine Stump 63fbe529fc conf: add passt XML additions to schema
Initial support for network devices using passt (https://passt.top)
for the backend connection will require:

* new attributes of the <backend> subelement:
  * "type" that can have the value "passt" (to differentiate from
    slirp, because both slirp and passt will use <interface
    type='user'>)
  * "logFile" (a path to a file that passt should use for its logging)
  * "upstream" (a netdev name, e.g. "eth0").

* a new subelement <portForward> (described in more detail later)

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2023-01-09 14:24:27 -05:00
Laine Stump efd286a760 conf: put interface <backend> parsing/formatting separate functions
In preparation for adding more stuff to <backend>.

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2023-01-09 14:24:27 -05:00
Laine Stump 7f6bb51eb9 conf: move anonymous backend struct from virDomainNetDef into its own struct
This will allow us to call parser/formatter functions with a pointer
to just the backend part.

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2023-01-09 14:24:27 -05:00
Laine Stump d3307a8fd2 conf: rename virDomainNetBackend* to virDomainNetDriver*
This fits better with the element containing the value (<driver>), and
allows us to use virDomainNetBackend* for things in the <backend>
element.

Signed-off-by: Laine Stump <laine@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2023-01-09 14:24:27 -05:00
Jiang Jiacheng 49ff47269b virNWFilterSaveConfig: remove the unnecessary variable 'ret'
Signed-off-by: Jiang Jiacheng <jiangjiacheng@huawei.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
Signed-off-by: Ján Tomko <jtomko@redhat.com>
2023-01-09 16:02:40 +01:00
Peter Krempa fe6077585e qemuxml2*test: Enable testing of disks with 'fdgroup'
Enable the qemuxml2xml variant and add output data for qemuxml2argvtest.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa 894fe89484 qemu: Enable support for FD passed disk sources
Assert support for VIR_DOMAIN_DEF_FEATURE_DISK_FD in the qemu driver
now that all code paths are adapted.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa a575aa280d qemu: cgroup: Don't setup cgroups for FD-passed images
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa dc20b1d774 qemu: driver: Don't allow certain operations with FD-passed disks
Probing stats and block copy to a FD passed image is not yet supported.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa 7ce63d5a07 qemu: Prepare storage backing chain traversal code for FD passed images
We assume that FD passed images already exist so all existance checks
are skipped.

For the case that a FD-passed image is passed without a terminated
backing chain (thus forcing us to detect) we attempt to read the header
from the FD.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa 6f3d13bfbd security: selinux: Handle security labelling of FD-passed images
Unfortunately unlike with DAC we can't simply ignore labelling for the
FD and it also influences the on-disk state.

Thus we need to relabel the FD and we also store the existing label in
cases when the user will request best-effort label replacement.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa 7fceb5e168 secuirity: DAC: Don't relabel FD-passed virStorageSource images
DAC security label is irrelevant once you have the FD. Disable all
labelling for such images.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa 74f3f4b93c qemu: block: Add support for passing FDs of disk images
Prepare the internal data for passing FDs instead of having qemu open
the file internally.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa 81cbfc2fc3 qemu: Prepare data for FD-passed disk image sources
When starting up a VM with FD-passed images we need to look up the
corresponding named FD set and associate it with the virStorageSource
based on the name.

The association is brought into virStorageSource as security labelling
code will need to access the FD to perform selinux labelling.

Similarly when startup is complete in certain cases we no longer need to
keep the copy of FDs and thus can close them.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa 47b922f3f8 conf: storage_source: Introduce virStorageSourceIsFD
The helper will be used in various places that need to check that a disk
source struct is using FD passing.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa 4c9ce062d3 qemu: domain: Introduce qemuDomainStartupCleanup
The new helper qemuDomainStartupCleanup is used to perform cleanup after
a startup of a VM (successful or not). The initial implementation just
calls qemuDomainSecretDestroy, which can be un-exported.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:43 +01:00
Peter Krempa 98bd201678 conf: Add 'fdgroup' attribute for 'file' disks
The 'fdgroup' will allow users to specify a passed FD (via the
'virDomainFDAssociate()' API) to be used instead of opening a path.
This is useful in cases when e.g. the file is not accessible from inside
a container.

Since this uses the same disk type as when we open files via names this
patch also introduces a hypervisor feature which the hypervisor asserts
that code paths are ready for this possibility.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:42 +01:00
Peter Krempa 0fcdb512d4 qemuxml2argvtest: Add support for populating 'fds' in private data
Introduce a new argument type for testQemuInfoSetArgs named ARG_FD_GROUP
which allows users to instantiate tests with populated FD passing hash
table.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:42 +01:00
Peter Krempa f762f87534 qemu: Implement qemuDomainFDAssociate
Implement passing and storage of FDs for the qemu driver. The FD tuples
are g_object instances stored in a per-domain hash table and are
automatically removed once the connection is closed.

In the future we can consider supporting also to not tie the lifetime of
the passed FDs bound to the connection.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:42 +01:00
Peter Krempa e2670a63d2 conf: storage_source: Introduce type for storing FDs associated for storage
For FD-passing of disk sources we'll need to keep the FDs around.
Introduce a data type helper based on a g_object so that we get
reference counting.

One instance will (due to security labelling) will need to be part of
the virStorageSource struct thus it's declared in the storage_source_conf
module.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:42 +01:00
Peter Krempa 3ea4170551 virsh: Introduce 'dom-fd-associate' for invoking virDomainFDAssociate()
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:42 +01:00
Peter Krempa abd9025c2f lib: Introduce virDomainFDAssociate API
The API can be used to associate one or more (e.g. a RO and RW fd for a
disk backend image) FDs to a VM. They can be then used per definition.

The primary use case for now is for complex deployment where
libvirtd/virtqemud may be run inside a container and getting the image
into the container is complicated.

In the future it will also allow passing e.g. vhost FDs and other
resources to a VM without the need to have a filesystem representation
for it.

Passing raw FDs has few intricacies and thus libvirt will by default not
restore security labels.

Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:59:42 +01:00
Erik Skultety 3ebfeaa206 ci: Refresh and add Fedora 37 target
Signed-off-by: Erik Skultety <eskultet@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
2023-01-09 14:53:34 +01:00
Peter Krempa d9193ff92b qemu: Fix variable sizing issues with 'bandwidth' argument of qemuBlockCommit
The patch moving the code didn't faithfully represent the typecasting
of the 'bandwidth' variable needed to properly convert from the legacy
'unsigned long' argument which resulted in a build failure on 32 bit
systems:

../src/qemu/qemu_block.c: In function ‘qemuBlockCommit’:
../src/qemu/qemu_block.c:3249:23: error: comparison is always false due to limited range of data type [-Werror=type-limits]
 3249 |         if (bandwidth > LLONG_MAX >> 20) {
      |                       ^

Fix it by returning the check into qemuDomainBlockCommit as it's needed
only because of the legacy argument type in the old API and use
'unsigned long long' for qemuBlockCommit.

Fixes: f5a77198bf
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 14:40:39 +01:00
Peter Krempa 64366c0056 qemu: snapshot: Restructure control flow to detect errors sooner and work around compiler
Some compilers aren't happy when an automatically freed variable is used
just to free something (thus it's only assigned in the code):

When compiling qemuSnapshotDelete after recent commits they complain:

../src/qemu/qemu_snapshot.c:3153:61: error: variable 'delData' set but not used [-Werror,-Wunused-but-set-variable]
                g_autoslist(qemuSnapshotDeleteExternalData) delData = NULL;
                                                            ^

To work around the issue we can restructure the code which also has the
following semantic implications:
 - since qemuSnapshotDeleteExternalPrepare does validation we error out
   sooner than attempting to start the VM

 - we read the temporary variable at least in one code path

Fixes: 4a4d89a925
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
2023-01-09 14:13:25 +01:00
Peter Krempa bb80344fd0 virNWFilterSnoopLeaseFileLoad: Don't typecast 'ipl.timeout'
Use a temporary variable to avoid memory alignment issues on ARM:

../src/nwfilter/nwfilter_dhcpsnoop.c: In function ‘virNWFilterSnoopLeaseFileLoad’:
../src/nwfilter/nwfilter_dhcpsnoop.c:1745:20: error: cast increases required alignment of target type [-Werror=cast-align]
 1745 |                    (unsigned long long *) &ipl.timeout,
      |

Fixes: 0d278aa089
Signed-off-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
2023-01-09 13:54:56 +01:00
Pavel Hrdina 8858a3cc35 NEWS: document support for external snapshot deletion
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:20 +01:00
Pavel Hrdina 8702898569 api: document support for external snapshot deletion
Now that deletion of external snapshot is implemented document the
current virDomainSnapshotDelete supported state.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:19 +01:00
Pavel Hrdina 85931fce74 qemu_snapshot: enable deletion of external snapshots
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:18 +01:00
Pavel Hrdina cadbf40d05 qemu_process: abort snapshot delete when daemon starts
If the daemon crashes or is restarted while the snapshot delete is in
progress we have to handle it gracefully to not leave any block jobs
active.

For now we will simply abort the snapshot delete operation so user can
start it again. We need to refuse deleting external snapshots if there
is already another active job as we would have to figure out which jobs
we can abort.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:16 +01:00
Pavel Hrdina f474e80ac3 qemu_domain: store snapshotDelete in qemuDomainJobPrivate
When daemon is restarted and libvirt tries to recover domain jobs we
need to know if the snapshot job was a snapshot delete in order to
safely abort running QEMU block jobs.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:12 +01:00
Pavel Hrdina 565bcb5d79 qemu_snapshot: when deleting snapshot invalidate parent snapshot
When deleting external snapshots the operation may fail at any point
which could lead to situation that some disks finished the block commit
operation but for some disks it failed and the libvirt job ends.

In order to make sure that the qcow2 images are in consistent state
introduce new element "<snapshotDeleteInProgress/>" that will mark the
disk in snapshot metadata as invalid until the snapshot delete is
completed successfully.

This will prevent deleting snapshot with the invalid disk and in future
reverting to snapshot with the invalid disk.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:07 +01:00
Pavel Hrdina 7190582fbc qemu_snapshot: update metadata when deleting snapshots
With external snapshots we need to modify the metadata bit more then
what is required for internal snapshots. Mainly the storage source
location changes with every external snapshot.

This means that if we delete non-leaf snapshot we need to update all
children snapshots and modify the disk sources for all affected disks.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:06 +01:00
Pavel Hrdina e27f081967 qemu_snapshot: implement deletion of external snapshot
When deleting snapshot we are starting block-commit job over all disks
that are part of the snapshot.

This operation may fail as it writes data changes to the backing qcow2
image so we need to wait for all the disks to finish the operation and
wait for correct signal from QEMU. If deleting active snapshot we will
get `ready` signal and for inactive snapshots we need to disable
autofinalize in order to get `pending` signal.

At this point if commit for any disk fails for some reason and we abort
the VM is still in consistent state and user can fix the reason why the
deletion failed.

After that we do `pivot` or `finalize` if it's active snapshot or not to
finish the block job. It still may fail but there is nothing else we can
do about it.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:05 +01:00
Pavel Hrdina 4a4d89a925 qemu_snapshot: prepare data for external snapshot deletion
In order to save some CPU cycles we will collect all the necessary data
to delete external snapshot before we even start. They will be later
used by code that deletes the snapshots and updates metadata when
needed.

With external snapshots we need data that libvirt gets from running QEMU
process so if the VM is not running we need to start paused QEMU process
for the snapshot deletion and kill at afterwards.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:04 +01:00
Pavel Hrdina 2038c1cd3a qemu_snapshot: convert snapshot delete to async domain job
Deleting external snapshots will require to run it as async domain job,
the same way as we do for snapshot creation.

For internal snapshots modify the job mask in order to forbid any other
job to be started.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:02 +01:00
Pavel Hrdina f5def5cd11 qemu_snapshot: error out when deleting internal snapshot on non-active disk
Deleting internal snapshot when the currently active disk image is
different than where the internal snapshot was taken doesn't work
correctly.

This applies to a running VM only as we are using QMP command and
talking to the QEMU process that is using different disk.

This works correctly when the VM is shut of as in this case we spawn
qemu-img process to delete the snapshot.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:33:01 +01:00
Pavel Hrdina 4475c69787 qemu_snapshot: refactor validation of snapshot delete
Prepare the validation function for external snapshot delete support.

There is one exception when deleting `children-only` snapshots. If the
snapshot tree is like this example:

    snap1 (external)
     |
     +- snap2 (internal)
         |
         +- snap3 (internal)
             |
             +- snap4 (internal)

and user calls `snapshot-delete snap1 --children-only` the current
snapshot is external but all the children snapshots are internal only
and we are able to delete it.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:59 +01:00
Pavel Hrdina 86883588c7 qemu_snapshot: introduce qemuSnapshotDeleteValidate function
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:58 +01:00
Pavel Hrdina 691fd8f3e3 qemu_snapshot: introduce qemuSnapshotDiscardMetadata
Extract the code deleting external snapshot metadata to separate
function.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:57 +01:00
Pavel Hrdina deb35939ee qemu_snapshot: move snapshot metadata reparent code
Previously the reparent happened before the actual snapshot deletion.
This change moves the code closer to the rest of the code handling
snapshot metadata when deletion happens. This makes the metadate
deletion happen after the data files are deleted.

Following patch will extract it into separate function

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:56 +01:00
Pavel Hrdina 9dd19a7a43 qemu_snapshot: move snapshot discard out of qemu_domain.c
Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:55 +01:00
Pavel Hrdina f5bde47d6c qemu_snapshot: rework snapshot children deletion
This simplifies the code a bit by reusing existing parts that deletes
a single snapshot.

The drawback of this change is that we will now call the re-parent bits
to keep the metadata in sync for every child even though it will get
deleted as well.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:53 +01:00
Pavel Hrdina a3c8c7e37a qemu_snapshot: introduce qemuSnapshotDeleteChildren
Extract code that deletes children of specific snapshot to separate
function.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:52 +01:00
Pavel Hrdina 7a6e5c5013 qemu_snapshot: introduce qemuSnapshotDeleteSingle
Extract code that deletes single snapshot to separate function.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:51 +01:00
Pavel Hrdina 06c2382ab9 qemu_snapshot: refactor qemuSnapshotDelete
Move code around to make it clear what is called when deleting single
snapshot or children snapshots.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:50 +01:00
Pavel Hrdina a784d4076a storage_source: introduce virStorageSourceChainLookupBySource
Looks up disk storage source within storage source chain using storage
source object instead of path to make it work with all disk types.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:49 +01:00
Pavel Hrdina 90d9bc9d74 qemu_blockjob: process QEMU_MONITOR_JOB_STATUS_PENDING signal
QEMU emits this signal when the job finished its work and is about to be
finalized. If the job is started with autofinalize disabled the job
waits for user input to finalize the job.

This will be used by snapshot delete code.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:48 +01:00
Pavel Hrdina 2686738b6c qemu_block: change qemuBlockCommit to return job pointer
The created job will be needed by external snapshot delete code so
rework qemuBlockCommit to return that pointer.

Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2023-01-09 13:32:47 +01:00