]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
pci: cleanup pci: unregister mdev directly inline
[qemu-server.git] / PVE / QemuServer.pm
CommitLineData
baa4f62d 1package PVE::QemuServer;
1e3baf05
DM
2
3use strict;
990fc5e2 4use warnings;
3ff84d6f 5
5da072fb
TL
6use Cwd 'abs_path';
7use Digest::SHA;
8use Fcntl ':flock';
9use Fcntl;
1e3baf05 10use File::Basename;
5da072fb 11use File::Copy qw(copy);
1e3baf05
DM
12use File::Path;
13use File::stat;
14use Getopt::Long;
5da072fb
TL
15use IO::Dir;
16use IO::File;
17use IO::Handle;
18use IO::Select;
19use IO::Socket::UNIX;
1e3baf05 20use IPC::Open3;
c971c4f2 21use JSON;
1f30ac3a 22use MIME::Base64;
5da072fb
TL
23use POSIX;
24use Storable qw(dclone);
f85951dc 25use Time::HiRes qw(gettimeofday usleep);
5da072fb 26use URI::Escape;
425441e6 27use UUID;
5da072fb 28
82841214 29use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file);
5b65b00d 30use PVE::CGroup;
83870398 31use PVE::CpuSet;
48cf040f 32use PVE::DataCenterConfig;
5da072fb 33use PVE::Exception qw(raise raise_param_exc);
3b56383b 34use PVE::Format qw(render_duration render_bytes);
81d6e4e1 35use PVE::GuestHelpers qw(safe_string_ne safe_num_ne safe_boolean_ne);
1e3baf05 36use PVE::INotify;
4df98f2f 37use PVE::JSONSchema qw(get_standard_option parse_property_string);
1e3baf05 38use PVE::ProcFSTools;
fbec3f89 39use PVE::PBSClient;
34e82fa2 40use PVE::RESTEnvironment qw(log_warn);
91bd6c90 41use PVE::RPCEnvironment;
5da072fb 42use PVE::Storage;
b71351a7 43use PVE::SysFSTools;
d04d6af1 44use PVE::Systemd;
82841214 45use PVE::Tools qw(run_command file_read_firstline file_get_contents dir_glob_foreach get_host_arch $IPV6RE);
5da072fb
TL
46
47use PVE::QMPClient;
48use PVE::QemuConfig;
2f18c84d 49use PVE::QemuServer::Helpers qw(min_version config_aware_timeout);
5da072fb 50use PVE::QemuServer::Cloudinit;
5b65b00d 51use PVE::QemuServer::CGroup;
d786a274 52use PVE::QemuServer::CPUConfig qw(print_cpu_device get_cpu_options);
75748d44 53use PVE::QemuServer::Drive qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom drive_is_read_only parse_drive print_drive);
2ea5fb7e 54use PVE::QemuServer::Machine;
5da072fb 55use PVE::QemuServer::Memory;
0a13e08e 56use PVE::QemuServer::Monitor qw(mon_cmd);
74c17b7a 57use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
5da072fb 58use PVE::QemuServer::USB qw(parse_usb_device);
1e3baf05 59
28e129cc
AD
60my $have_sdn;
61eval {
62 require PVE::Network::SDN::Zones;
63 $have_sdn = 1;
64};
65
102cf9d8 66my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
96ed3574 67my $OVMF = {
b5099b4f 68 x86_64 => {
90b20b15
DC
69 '4m-no-smm' => [
70 "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
71 "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
72 ],
73 '4m-no-smm-ms' => [
74 "$EDK2_FW_BASE/OVMF_CODE_4M.fd",
75 "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
76 ],
b5099b4f
SR
77 '4m' => [
78 "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
79 "$EDK2_FW_BASE/OVMF_VARS_4M.fd",
80 ],
81 '4m-ms' => [
82 "$EDK2_FW_BASE/OVMF_CODE_4M.secboot.fd",
83 "$EDK2_FW_BASE/OVMF_VARS_4M.ms.fd",
84 ],
85 default => [
86 "$EDK2_FW_BASE/OVMF_CODE.fd",
87 "$EDK2_FW_BASE/OVMF_VARS.fd",
88 ],
89 },
90 aarch64 => {
91 default => [
92 "$EDK2_FW_BASE/AAVMF_CODE.fd",
93 "$EDK2_FW_BASE/AAVMF_VARS.fd",
94 ],
95 },
96ed3574 96};
2ddc0a5c 97
7f0b5beb 98my $cpuinfo = PVE::ProcFSTools::read_cpuinfo();
1e3baf05 99
8d88a594
TL
100# Note about locking: we use flock on the config file protect against concurent actions.
101# Aditionaly, we have a 'lock' setting in the config file. This can be set to 'migrate',
102# 'backup', 'snapshot' or 'rollback'. Most actions are not allowed when such lock is set.
103# But you can ignore this kind of lock with the --skiplock flag.
1e3baf05 104
97d62eb7 105cfs_register_file('/qemu-server/',
1858638f
DM
106 \&parse_vm_config,
107 \&write_vm_config);
1e3baf05 108
3ea94c60
DM
109PVE::JSONSchema::register_standard_option('pve-qm-stateuri', {
110 description => "Some command save/restore state from this location.",
111 type => 'string',
112 maxLength => 128,
113 optional => 1,
114});
115
c6737ef1
DC
116PVE::JSONSchema::register_standard_option('pve-qemu-machine', {
117 description => "Specifies the Qemu machine type.",
118 type => 'string',
9471e48b 119 pattern => '(pc|pc(-i440fx)?-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|q35|pc-q35-\d+(\.\d+)+(\+pve\d+)?(\.pxe)?|virt(?:-\d+(\.\d+)+)?(\+pve\d+)?)',
c6737ef1
DC
120 maxLength => 40,
121 optional => 1,
122});
123
1e3baf05
DM
124#no warnings 'redefine';
125
38277afc
TL
126my $nodename_cache;
127sub nodename {
128 $nodename_cache //= PVE::INotify::nodename();
129 return $nodename_cache;
130}
1e3baf05 131
ec3582b5
WB
132my $watchdog_fmt = {
133 model => {
134 default_key => 1,
135 type => 'string',
136 enum => [qw(i6300esb ib700)],
137 description => "Watchdog type to emulate.",
138 default => 'i6300esb',
139 optional => 1,
140 },
141 action => {
142 type => 'string',
143 enum => [qw(reset shutdown poweroff pause debug none)],
144 description => "The action to perform if after activation the guest fails to poll the watchdog in time.",
145 optional => 1,
146 },
147};
148PVE::JSONSchema::register_format('pve-qm-watchdog', $watchdog_fmt);
149
9d66b397
SI
150my $agent_fmt = {
151 enabled => {
8d88a594 152 description => "Enable/disable communication with a Qemu Guest Agent (QGA) running in the VM.",
9d66b397
SI
153 type => 'boolean',
154 default => 0,
155 default_key => 1,
156 },
157 fstrim_cloned_disks => {
0a4aff09 158 description => "Run fstrim after moving a disk or migrating the VM.",
9d66b397
SI
159 type => 'boolean',
160 optional => 1,
161 default => 0
162 },
48657158
MD
163 type => {
164 description => "Select the agent type",
165 type => 'string',
166 default => 'virtio',
167 optional => 1,
168 enum => [qw(virtio isa)],
169 },
9d66b397
SI
170};
171
55655ebc
DC
172my $vga_fmt = {
173 type => {
174 description => "Select the VGA type.",
175 type => 'string',
176 default => 'std',
177 optional => 1,
178 default_key => 1,
6f070e39 179 enum => [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio virtio-gl vmware)],
55655ebc
DC
180 },
181 memory => {
182 description => "Sets the VGA memory (in MiB). Has no effect with serial display.",
183 type => 'integer',
184 optional => 1,
185 minimum => 4,
186 maximum => 512,
187 },
188};
189
6dbcb073
DC
190my $ivshmem_fmt = {
191 size => {
192 type => 'integer',
193 minimum => 1,
194 description => "The size of the file in MB.",
195 },
196 name => {
197 type => 'string',
198 pattern => '[a-zA-Z0-9\-]+',
199 optional => 1,
200 format_description => 'string',
201 description => "The name of the file. Will be prefixed with 'pve-shm-'. Default is the VMID. Will be deleted when the VM is stopped.",
202 },
203};
204
1448547f
AL
205my $audio_fmt = {
206 device => {
207 type => 'string',
208 enum => [qw(ich9-intel-hda intel-hda AC97)],
209 description => "Configure an audio device."
210 },
211 driver => {
212 type => 'string',
211785ee 213 enum => ['spice', 'none'],
1448547f
AL
214 default => 'spice',
215 optional => 1,
216 description => "Driver backend for the audio device."
217 },
218};
219
c4df18db
AL
220my $spice_enhancements_fmt = {
221 foldersharing => {
222 type => 'boolean',
223 optional => 1,
d282a24d 224 default => '0',
c4df18db
AL
225 description => "Enable folder sharing via SPICE. Needs Spice-WebDAV daemon installed in the VM."
226 },
227 videostreaming => {
228 type => 'string',
229 enum => ['off', 'all', 'filter'],
d282a24d 230 default => 'off',
c4df18db
AL
231 optional => 1,
232 description => "Enable video streaming. Uses compression for detected video streams."
233 },
234};
235
2cf61f33
SR
236my $rng_fmt = {
237 source => {
238 type => 'string',
239 enum => ['/dev/urandom', '/dev/random', '/dev/hwrng'],
240 default_key => 1,
8d88a594
TL
241 description => "The file on the host to gather entropy from. In most cases '/dev/urandom'"
242 ." should be preferred over '/dev/random' to avoid entropy-starvation issues on the"
243 ." host. Using urandom does *not* decrease security in any meaningful way, as it's"
244 ." still seeded from real entropy, and the bytes provided will most likely be mixed"
245 ." with real entropy on the guest as well. '/dev/hwrng' can be used to pass through"
246 ." a hardware RNG from the host.",
2cf61f33
SR
247 },
248 max_bytes => {
249 type => 'integer',
8d88a594
TL
250 description => "Maximum bytes of entropy allowed to get injected into the guest every"
251 ." 'period' milliseconds. Prefer a lower value when using '/dev/random' as source. Use"
252 ." `0` to disable limiting (potentially dangerous!).",
2cf61f33
SR
253 optional => 1,
254
8d88a594
TL
255 # default is 1 KiB/s, provides enough entropy to the guest to avoid boot-starvation issues
256 # (e.g. systemd etc...) while allowing no chance of overwhelming the host, provided we're
257 # reading from /dev/urandom
2cf61f33
SR
258 default => 1024,
259 },
260 period => {
261 type => 'integer',
8d88a594
TL
262 description => "Every 'period' milliseconds the entropy-injection quota is reset, allowing"
263 ." the guest to retrieve another 'max_bytes' of entropy.",
2cf61f33
SR
264 optional => 1,
265 default => 1000,
266 },
267};
268
26b443c8
TL
269my $meta_info_fmt = {
270 'ctime' => {
271 type => 'integer',
272 description => "The guest creation timestamp as UNIX epoch time",
273 minimum => 0,
274 optional => 1,
275 },
af2a1a1c
TL
276 'creation-qemu' => {
277 type => 'string',
278 description => "The QEMU (machine) version from the time this VM was created.",
279 pattern => '\d+(\.\d+)+',
280 optional => 1,
281 },
26b443c8
TL
282};
283
1e3baf05
DM
284my $confdesc = {
285 onboot => {
286 optional => 1,
287 type => 'boolean',
288 description => "Specifies whether a VM will be started during system bootup.",
289 default => 0,
290 },
291 autostart => {
292 optional => 1,
293 type => 'boolean',
294 description => "Automatic restart after crash (currently ignored).",
295 default => 0,
296 },
2ff09f52 297 hotplug => {
483ceeab
TL
298 optional => 1,
299 type => 'string', format => 'pve-hotplug-features',
300 description => "Selectively enable hotplug features. This is a comma separated list of"
94ec5e7c 301 ." hotplug features: 'network', 'disk', 'cpu', 'memory', 'usb' and 'cloudinit'. Use '0' to disable"
8d88a594 302 ." hotplug completely. Using '1' as value is an alias for the default `network,disk,usb`.",
b3c2bdd1 303 default => 'network,disk,usb',
2ff09f52 304 },
1e3baf05
DM
305 reboot => {
306 optional => 1,
307 type => 'boolean',
308 description => "Allow reboot. If set to '0' the VM exit on reboot.",
309 default => 1,
310 },
311 lock => {
312 optional => 1,
313 type => 'string',
314 description => "Lock/unlock the VM.",
159719e5 315 enum => [qw(backup clone create migrate rollback snapshot snapshot-delete suspending suspended)],
1e3baf05
DM
316 },
317 cpulimit => {
318 optional => 1,
c6f773b8 319 type => 'number',
52261945 320 description => "Limit of CPU usage.",
8d88a594
TL
321 verbose_description => "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has"
322 ." total of '2' CPU time. Value '0' indicates no CPU limit.",
1e3baf05 323 minimum => 0,
c6f773b8 324 maximum => 128,
483ceeab 325 default => 0,
1e3baf05
DM
326 },
327 cpuunits => {
328 optional => 1,
329 type => 'integer',
483ceeab 330 description => "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
67498860
TL
331 verbose_description => "CPU weight for a VM. Argument is used in the kernel fair scheduler."
332 ." The larger the number is, the more CPU time this VM gets. Number is relative to"
333 ." weights of all the other running VMs.",
e65e35ca 334 minimum => 1,
237239bf 335 maximum => 262144,
67498860 336 default => 'cgroup v1: 1024, cgroup v2: 100',
1e3baf05
DM
337 },
338 memory => {
339 optional => 1,
340 type => 'integer',
8d88a594
TL
341 description => "Amount of RAM for the VM in MB. This is the maximum available memory when"
342 ." you use the balloon device.",
1e3baf05
DM
343 minimum => 16,
344 default => 512,
345 },
13a48620 346 balloon => {
483ceeab
TL
347 optional => 1,
348 type => 'integer',
349 description => "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
8b1accf7
DM
350 minimum => 0,
351 },
352 shares => {
483ceeab
TL
353 optional => 1,
354 type => 'integer',
355 description => "Amount of memory shares for auto-ballooning. The larger the number is, the"
8d88a594
TL
356 ." more memory this VM gets. Number is relative to weights of all other running VMs."
357 ." Using zero disables auto-ballooning. Auto-ballooning is done by pvestatd.",
8b1accf7
DM
358 minimum => 0,
359 maximum => 50000,
360 default => 1000,
13a48620 361 },
1e3baf05
DM
362 keyboard => {
363 optional => 1,
364 type => 'string',
233fb336
DW
365 description => "Keyboard layout for VNC server. This option is generally not required and"
366 ." is often better handled from within the guest OS.",
e95fe75f 367 enum => PVE::Tools::kvmkeymaplist(),
aea47dd6 368 default => undef,
1e3baf05
DM
369 },
370 name => {
371 optional => 1,
7fabe17d 372 type => 'string', format => 'dns-name',
1e3baf05
DM
373 description => "Set a name for the VM. Only used on the configuration web interface.",
374 },
cdd20088
AD
375 scsihw => {
376 optional => 1,
377 type => 'string',
52261945 378 description => "SCSI controller model",
6731a4cf 379 enum => [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
cdd20088
AD
380 default => 'lsi',
381 },
1e3baf05
DM
382 description => {
383 optional => 1,
384 type => 'string',
a200af10
TL
385 description => "Description for the VM. Shown in the web-interface VM's summary."
386 ." This is saved as comment inside the configuration file.",
387 maxLength => 1024 * 8,
1e3baf05
DM
388 },
389 ostype => {
390 optional => 1,
391 type => 'string',
483ceeab 392 enum => [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 win11 l24 l26 solaris)],
52261945
DM
393 description => "Specify guest operating system.",
394 verbose_description => <<EODESC,
395Specify guest operating system. This is used to enable special
396optimization/features for specific operating systems:
397
398[horizontal]
399other;; unspecified OS
400wxp;; Microsoft Windows XP
401w2k;; Microsoft Windows 2000
402w2k3;; Microsoft Windows 2003
403w2k8;; Microsoft Windows 2008
404wvista;; Microsoft Windows Vista
405win7;; Microsoft Windows 7
44c2a647 406win8;; Microsoft Windows 8/2012/2012r2
1f5828f2 407win10;; Microsoft Windows 10/2016/2019
179b9f1b 408win11;; Microsoft Windows 11/2022
52261945 409l24;; Linux 2.4 Kernel
a5269260 410l26;; Linux 2.6 - 5.X Kernel
52261945 411solaris;; Solaris/OpenSolaris/OpenIndiania kernel
1e3baf05
DM
412EODESC
413 },
414 boot => {
415 optional => 1,
2141a802 416 type => 'string', format => 'pve-qm-boot',
483ceeab
TL
417 description => "Specify guest boot order. Use the 'order=' sub-property as usage with no"
418 ." key or 'legacy=' is deprecated.",
1e3baf05
DM
419 },
420 bootdisk => {
421 optional => 1,
422 type => 'string', format => 'pve-qm-bootdisk',
2141a802 423 description => "Enable booting from specified disk. Deprecated: Use 'boot: order=foo;bar' instead.",
03e480fc 424 pattern => '(ide|sata|scsi|virtio)\d+',
1e3baf05
DM
425 },
426 smp => {
427 optional => 1,
428 type => 'integer',
429 description => "The number of CPUs. Please use option -sockets instead.",
430 minimum => 1,
431 default => 1,
432 },
433 sockets => {
434 optional => 1,
435 type => 'integer',
436 description => "The number of CPU sockets.",
437 minimum => 1,
438 default => 1,
439 },
440 cores => {
441 optional => 1,
442 type => 'integer',
443 description => "The number of cores per socket.",
444 minimum => 1,
445 default => 1,
446 },
8a010eae
AD
447 numa => {
448 optional => 1,
449 type => 'boolean',
1917695c 450 description => "Enable/disable NUMA.",
8a010eae
AD
451 default => 0,
452 },
7023f3ea
AD
453 hugepages => {
454 optional => 1,
455 type => 'string',
456 description => "Enable/disable hugepages memory.",
457 enum => [qw(any 2 1024)],
458 },
f36e9894
SR
459 keephugepages => {
460 optional => 1,
461 type => 'boolean',
462 default => 0,
4df98f2f
TL
463 description => "Use together with hugepages. If enabled, hugepages will not not be deleted"
464 ." after VM shutdown and can be used for subsequent starts.",
f36e9894 465 },
de9d1e55 466 vcpus => {
3bd18e48
AD
467 optional => 1,
468 type => 'integer',
de9d1e55 469 description => "Number of hotplugged vcpus.",
3bd18e48 470 minimum => 1,
de9d1e55 471 default => 0,
3bd18e48 472 },
1e3baf05
DM
473 acpi => {
474 optional => 1,
475 type => 'boolean',
476 description => "Enable/disable ACPI.",
477 default => 1,
478 },
bc84dcca 479 agent => {
ab6a046f 480 optional => 1,
8d88a594 481 description => "Enable/disable communication with the Qemu Guest Agent and its properties.",
9d66b397
SI
482 type => 'string',
483 format => $agent_fmt,
ab6a046f 484 },
1e3baf05
DM
485 kvm => {
486 optional => 1,
487 type => 'boolean',
488 description => "Enable/disable KVM hardware virtualization.",
489 default => 1,
490 },
491 tdf => {
492 optional => 1,
493 type => 'boolean',
8c559505
DM
494 description => "Enable/disable time drift fix.",
495 default => 0,
1e3baf05 496 },
19672434 497 localtime => {
1e3baf05
DM
498 optional => 1,
499 type => 'boolean',
8d88a594
TL
500 description => "Set the real time clock (RTC) to local time. This is enabled by default if"
501 ." the `ostype` indicates a Microsoft Windows OS.",
1e3baf05
DM
502 },
503 freeze => {
504 optional => 1,
505 type => 'boolean',
506 description => "Freeze CPU at startup (use 'c' monitor command to start execution).",
507 },
508 vga => {
509 optional => 1,
55655ebc
DC
510 type => 'string', format => $vga_fmt,
511 description => "Configure the VGA hardware.",
4df98f2f
TL
512 verbose_description => "Configure the VGA Hardware. If you want to use high resolution"
513 ." modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU"
514 ." 2.9 the default VGA display type is 'std' for all OS types besides some Windows"
515 ." versions (XP and older) which use 'cirrus'. The 'qxl' option enables the SPICE"
516 ." display server. For win* OS you can select how many independent displays you want,"
517 ." Linux guests can add displays them self.\nYou can also run without any graphic card,"
518 ." using a serial device as terminal.",
1e3baf05 519 },
0ea9541d
DM
520 watchdog => {
521 optional => 1,
522 type => 'string', format => 'pve-qm-watchdog',
52261945 523 description => "Create a virtual hardware watchdog device.",
4df98f2f
TL
524 verbose_description => "Create a virtual hardware watchdog device. Once enabled (by a guest"
525 ." action), the watchdog must be periodically polled by an agent inside the guest or"
526 ." else the watchdog will reset the guest (or execute the respective action specified)",
0ea9541d 527 },
1e3baf05
DM
528 startdate => {
529 optional => 1,
19672434 530 type => 'string',
1e3baf05 531 typetext => "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
4df98f2f
TL
532 description => "Set the initial date of the real time clock. Valid format for date are:"
533 ."'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
1e3baf05
DM
534 pattern => '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
535 default => 'now',
536 },
43574f73 537 startup => get_standard_option('pve-startup-order'),
68eda3ab
AD
538 template => {
539 optional => 1,
540 type => 'boolean',
541 description => "Enable/disable Template.",
542 default => 0,
543 },
1e3baf05
DM
544 args => {
545 optional => 1,
546 type => 'string',
52261945
DM
547 description => "Arbitrary arguments passed to kvm.",
548 verbose_description => <<EODESCR,
c7a8aad6 549Arbitrary arguments passed to kvm, for example:
1e3baf05
DM
550
551args: -no-reboot -no-hpet
c7a8aad6
FG
552
553NOTE: this option is for experts only.
1e3baf05
DM
554EODESCR
555 },
556 tablet => {
557 optional => 1,
558 type => 'boolean',
559 default => 1,
52261945 560 description => "Enable/disable the USB tablet device.",
4df98f2f
TL
561 verbose_description => "Enable/disable the USB tablet device. This device is usually needed"
562 ." to allow absolute mouse positioning with VNC. Else the mouse runs out of sync with"
563 ." normal VNC clients. If you're running lots of console-only guests on one host, you"
564 ." may consider disabling this to save some context switches. This is turned off by"
565 ." default if you use spice (`qm set <vmid> --vga qxl`).",
1e3baf05
DM
566 },
567 migrate_speed => {
568 optional => 1,
569 type => 'integer',
570 description => "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
571 minimum => 0,
572 default => 0,
573 },
574 migrate_downtime => {
575 optional => 1,
04432191 576 type => 'number',
1e3baf05
DM
577 description => "Set maximum tolerated downtime (in seconds) for migrations.",
578 minimum => 0,
04432191 579 default => 0.1,
1e3baf05
DM
580 },
581 cdrom => {
582 optional => 1,
b799312f 583 type => 'string', format => 'pve-qm-ide',
8485b9ba 584 typetext => '<volume>',
1e3baf05
DM
585 description => "This is an alias for option -ide2",
586 },
587 cpu => {
588 optional => 1,
589 description => "Emulated CPU type.",
590 type => 'string',
5d008ad3 591 format => 'pve-vm-cpu-conf',
1e3baf05 592 },
b7ba6b79
DM
593 parent => get_standard_option('pve-snapshot-name', {
594 optional => 1,
595 description => "Parent snapshot name. This is used internally, and should not be modified.",
596 }),
982c7f12
DM
597 snaptime => {
598 optional => 1,
599 description => "Timestamp for snapshots.",
600 type => 'integer',
601 minimum => 0,
602 },
18bfb361
DM
603 vmstate => {
604 optional => 1,
605 type => 'string', format => 'pve-volume-id',
4df98f2f
TL
606 description => "Reference to a volume which stores the VM state. This is used internally"
607 ." for snapshots.",
18bfb361 608 },
253624c7
FG
609 vmstatestorage => get_standard_option('pve-storage-id', {
610 description => "Default storage for VM state volumes/files.",
611 optional => 1,
612 }),
c6737ef1 613 runningmachine => get_standard_option('pve-qemu-machine', {
4df98f2f
TL
614 description => "Specifies the QEMU machine type of the running vm. This is used internally"
615 ." for snapshots.",
c6737ef1 616 }),
ea1c2110 617 runningcpu => {
4df98f2f
TL
618 description => "Specifies the QEMU '-cpu' parameter of the running vm. This is used"
619 ." internally for snapshots.",
ea1c2110
SR
620 optional => 1,
621 type => 'string',
622 pattern => $PVE::QemuServer::CPUConfig::qemu_cmdline_cpu_re,
623 format_description => 'QEMU -cpu parameter'
624 },
c6737ef1 625 machine => get_standard_option('pve-qemu-machine'),
d731ecbe
WB
626 arch => {
627 description => "Virtual processor architecture. Defaults to the host.",
628 optional => 1,
629 type => 'string',
630 enum => [qw(x86_64 aarch64)],
631 },
2796e7d5
DM
632 smbios1 => {
633 description => "Specify SMBIOS type 1 fields.",
634 type => 'string', format => 'pve-qm-smbios1',
5d004b00 635 maxLength => 512,
2796e7d5
DM
636 optional => 1,
637 },
cb0e4540
AG
638 protection => {
639 optional => 1,
640 type => 'boolean',
4df98f2f
TL
641 description => "Sets the protection flag of the VM. This will disable the remove VM and"
642 ." remove disk operations.",
cb0e4540
AG
643 default => 0,
644 },
3edb45e7 645 bios => {
a783c78e 646 optional => 1,
3edb45e7
DM
647 type => 'string',
648 enum => [ qw(seabios ovmf) ],
649 description => "Select BIOS implementation.",
650 default => 'seabios',
a783c78e 651 },
6ee499ff
DC
652 vmgenid => {
653 type => 'string',
654 pattern => '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
655 format_description => 'UUID',
4df98f2f
TL
656 description => "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0'"
657 ." to disable explicitly.",
658 verbose_description => "The VM generation ID (vmgenid) device exposes a 128-bit integer"
659 ." value identifier to the guest OS. This allows to notify the guest operating system"
660 ." when the virtual machine is executed with a different configuration (e.g. snapshot"
661 ." execution or creation from a template). The guest operating system notices the"
662 ." change, and is then able to react as appropriate by marking its copies of"
663 ." distributed databases as dirty, re-initializing its random number generator, etc.\n"
664 ."Note that auto-creation only works when done through API/CLI create or update methods"
665 .", but not when manually editing the config file.",
f7ed64e7 666 default => "1 (autogenerated)",
6ee499ff
DC
667 optional => 1,
668 },
9e784b11
DC
669 hookscript => {
670 type => 'string',
671 format => 'pve-volume-id',
672 optional => 1,
673 description => "Script that will be executed during various steps in the vms lifetime.",
674 },
6dbcb073
DC
675 ivshmem => {
676 type => 'string',
677 format => $ivshmem_fmt,
4df98f2f
TL
678 description => "Inter-VM shared memory. Useful for direct communication between VMs, or to"
679 ." the host.",
6dbcb073 680 optional => 1,
2e7b5925
AL
681 },
682 audio0 => {
683 type => 'string',
1448547f 684 format => $audio_fmt,
194b65f1 685 description => "Configure a audio device, useful in combination with QXL/Spice.",
2e7b5925
AL
686 optional => 1
687 },
c4df18db
AL
688 spice_enhancements => {
689 type => 'string',
690 format => $spice_enhancements_fmt,
691 description => "Configure additional enhancements for SPICE.",
692 optional => 1
693 },
b8e7068a
DC
694 tags => {
695 type => 'string', format => 'pve-tag-list',
696 description => 'Tags of the VM. This is only meta information.',
697 optional => 1,
698 },
2cf61f33
SR
699 rng0 => {
700 type => 'string',
701 format => $rng_fmt,
702 description => "Configure a VirtIO-based Random Number Generator.",
703 optional => 1,
704 },
26b443c8
TL
705 meta => {
706 type => 'string',
707 format => $meta_info_fmt,
708 description => "Some (read-only) meta-information about this guest.",
709 optional => 1,
710 },
83870398
DB
711 affinity => {
712 type => 'string', format => 'pve-cpuset',
713 description => "List of host cores used to execute guest processes.",
714 optional => 1,
715 },
9ed7a77c
WB
716};
717
cb702ebe
DL
718my $cicustom_fmt = {
719 meta => {
720 type => 'string',
721 optional => 1,
4df98f2f
TL
722 description => 'Specify a custom file containing all meta data passed to the VM via"
723 ." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
cb702ebe
DL
724 format => 'pve-volume-id',
725 format_description => 'volume',
726 },
727 network => {
728 type => 'string',
729 optional => 1,
4df98f2f
TL
730 description => 'Specify a custom file containing all network data passed to the VM via'
731 .' cloud-init.',
cb702ebe
DL
732 format => 'pve-volume-id',
733 format_description => 'volume',
734 },
735 user => {
736 type => 'string',
737 optional => 1,
4df98f2f
TL
738 description => 'Specify a custom file containing all user data passed to the VM via'
739 .' cloud-init.',
cb702ebe
DL
740 format => 'pve-volume-id',
741 format_description => 'volume',
742 },
101beafe
CH
743 vendor => {
744 type => 'string',
745 optional => 1,
746 description => 'Specify a custom file containing all vendor data passed to the VM via'
747 .' cloud-init.',
748 format => 'pve-volume-id',
749 format_description => 'volume',
750 },
cb702ebe
DL
751};
752PVE::JSONSchema::register_format('pve-qm-cicustom', $cicustom_fmt);
753
9ed7a77c 754my $confdesc_cloudinit = {
41cd94a0
WB
755 citype => {
756 optional => 1,
757 type => 'string',
4df98f2f
TL
758 description => 'Specifies the cloud-init configuration format. The default depends on the'
759 .' configured operating system type (`ostype`. We use the `nocloud` format for Linux,'
760 .' and `configdrive2` for windows.',
545eec65 761 enum => ['configdrive2', 'nocloud', 'opennebula'],
41cd94a0 762 },
7b42f951
WB
763 ciuser => {
764 optional => 1,
765 type => 'string',
4df98f2f
TL
766 description => "cloud-init: User name to change ssh keys and password for instead of the"
767 ." image's configured default user.",
7b42f951
WB
768 },
769 cipassword => {
770 optional => 1,
771 type => 'string',
4df98f2f
TL
772 description => 'cloud-init: Password to assign the user. Using this is generally not'
773 .' recommended. Use ssh keys instead. Also note that older cloud-init versions do not'
774 .' support hashed passwords.',
7b42f951 775 },
cb702ebe
DL
776 cicustom => {
777 optional => 1,
778 type => 'string',
4df98f2f
TL
779 description => 'cloud-init: Specify custom files to replace the automatically generated'
780 .' ones at start.',
cb702ebe
DL
781 format => 'pve-qm-cicustom',
782 },
0c9a7596
AD
783 searchdomain => {
784 optional => 1,
785 type => 'string',
bd49ecb4 786 description => 'cloud-init: Sets DNS search domains for a container. Create will'
4df98f2f 787 .' automatically use the setting from the host if neither searchdomain nor nameserver'
bd49ecb4 788 .' are set.',
0c9a7596
AD
789 },
790 nameserver => {
791 optional => 1,
792 type => 'string', format => 'address-list',
bd49ecb4 793 description => 'cloud-init: Sets DNS server IP address for a container. Create will'
4df98f2f 794 .' automatically use the setting from the host if neither searchdomain nor nameserver'
bd49ecb4 795 .' are set.',
0c9a7596
AD
796 },
797 sshkeys => {
798 optional => 1,
799 type => 'string',
800 format => 'urlencoded',
1d1c4e1c 801 description => "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
0c9a7596 802 },
1e3baf05
DM
803};
804
805# what about other qemu settings ?
806#cpu => 'string',
807#machine => 'string',
808#fda => 'file',
809#fdb => 'file',
810#mtdblock => 'file',
811#sd => 'file',
812#pflash => 'file',
813#snapshot => 'bool',
814#bootp => 'file',
815##tftp => 'dir',
816##smb => 'dir',
817#kernel => 'file',
818#append => 'string',
819#initrd => 'file',
820##soundhw => 'string',
821
822while (my ($k, $v) = each %$confdesc) {
823 PVE::JSONSchema::register_standard_option("pve-qm-$k", $v);
824}
825
1e3baf05 826my $MAX_USB_DEVICES = 5;
5bdcf937 827my $MAX_NETS = 32;
bae179aa 828my $MAX_SERIAL_PORTS = 4;
1989a89c 829my $MAX_PARALLEL_PORTS = 3;
2ed5d572
AD
830my $MAX_NUMA = 8;
831
ffc0d8c7
WB
832my $numa_fmt = {
833 cpus => {
834 type => "string",
835 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
52261945 836 description => "CPUs accessing this NUMA node.",
ffc0d8c7
WB
837 format_description => "id[-id];...",
838 },
839 memory => {
840 type => "number",
52261945 841 description => "Amount of memory this NUMA node provides.",
ffc0d8c7
WB
842 optional => 1,
843 },
844 hostnodes => {
845 type => "string",
846 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
52261945 847 description => "Host NUMA nodes to use.",
ffc0d8c7
WB
848 format_description => "id[-id];...",
849 optional => 1,
850 },
851 policy => {
852 type => 'string',
853 enum => [qw(preferred bind interleave)],
52261945 854 description => "NUMA allocation policy.",
ffc0d8c7
WB
855 optional => 1,
856 },
857};
858PVE::JSONSchema::register_format('pve-qm-numanode', $numa_fmt);
2ed5d572
AD
859my $numadesc = {
860 optional => 1,
ffc0d8c7 861 type => 'string', format => $numa_fmt,
52261945 862 description => "NUMA topology.",
2ed5d572
AD
863};
864PVE::JSONSchema::register_standard_option("pve-qm-numanode", $numadesc);
865
866for (my $i = 0; $i < $MAX_NUMA; $i++) {
867 $confdesc->{"numa$i"} = $numadesc;
868}
1e3baf05 869
f7bc17ca
TL
870my $nic_model_list = [
871 'e1000',
872 'e1000-82540em',
873 'e1000-82544gc',
874 'e1000-82545em',
e83dd50a 875 'e1000e',
f7bc17ca
TL
876 'i82551',
877 'i82557b',
878 'i82559er',
879 'ne2k_isa',
880 'ne2k_pci',
881 'pcnet',
882 'rtl8139',
883 'virtio',
884 'vmxnet3',
885];
6b64503e 886my $nic_model_list_txt = join(' ', sort @$nic_model_list);
1e3baf05 887
52261945
DM
888my $net_fmt_bridge_descr = <<__EOD__;
889Bridge to attach the network device to. The Proxmox VE standard bridge
890is called 'vmbr0'.
891
892If you do not specify a bridge, we create a kvm user (NATed) network
893device, which provides DHCP and DNS services. The following addresses
894are used:
895
896 10.0.2.2 Gateway
897 10.0.2.3 DNS Server
898 10.0.2.4 SMB Server
899
900The DHCP server assign addresses to the guest starting from 10.0.2.15.
901__EOD__
902
cd9c34d1 903my $net_fmt = {
399d96db 904 macaddr => get_standard_option('mac-addr', {
4df98f2f
TL
905 description => "MAC address. That address must be unique withing your network. This is"
906 ." automatically generated if not specified.",
399d96db 907 }),
7f694a71
DM
908 model => {
909 type => 'string',
4df98f2f
TL
910 description => "Network Card Model. The 'virtio' model provides the best performance with"
911 ." very low CPU overhead. If your guest does not support this driver, it is usually"
912 ." best to use 'e1000'.",
7f694a71
DM
913 enum => $nic_model_list,
914 default_key => 1,
915 },
916 (map { $_ => { keyAlias => 'model', alias => 'macaddr' }} @$nic_model_list),
dbdcc5cd 917 bridge => get_standard_option('pve-bridge-id', {
52261945 918 description => $net_fmt_bridge_descr,
cd9c34d1 919 optional => 1,
dbdcc5cd 920 }),
cd9c34d1
WB
921 queues => {
922 type => 'integer',
923 minimum => 0, maximum => 16,
924 description => 'Number of packet queues to be used on the device.',
cd9c34d1
WB
925 optional => 1,
926 },
927 rate => {
928 type => 'number',
929 minimum => 0,
52261945 930 description => "Rate limit in mbps (megabytes per second) as floating point number.",
cd9c34d1
WB
931 optional => 1,
932 },
933 tag => {
934 type => 'integer',
9f41a659 935 minimum => 1, maximum => 4094,
cd9c34d1 936 description => 'VLAN tag to apply to packets on this interface.',
cd9c34d1
WB
937 optional => 1,
938 },
939 trunks => {
940 type => 'string',
941 pattern => qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
942 description => 'VLAN trunks to pass through this interface.',
7f694a71 943 format_description => 'vlanid[;vlanid...]',
cd9c34d1
WB
944 optional => 1,
945 },
946 firewall => {
947 type => 'boolean',
948 description => 'Whether this interface should be protected by the firewall.',
cd9c34d1
WB
949 optional => 1,
950 },
951 link_down => {
952 type => 'boolean',
52261945 953 description => 'Whether this interface should be disconnected (like pulling the plug).',
cd9c34d1
WB
954 optional => 1,
955 },
61a14cde
AD
956 mtu => {
957 type => 'integer',
958 minimum => 1, maximum => 65520,
0530177b 959 description => "Force MTU, for VirtIO only. Set to '1' to use the bridge MTU",
61a14cde
AD
960 optional => 1,
961 },
cd9c34d1 962};
52261945 963
1e3baf05
DM
964my $netdesc = {
965 optional => 1,
7f694a71 966 type => 'string', format => $net_fmt,
52261945 967 description => "Specify network devices.",
1e3baf05 968};
52261945 969
1e3baf05
DM
970PVE::JSONSchema::register_standard_option("pve-qm-net", $netdesc);
971
0c9a7596
AD
972my $ipconfig_fmt = {
973 ip => {
974 type => 'string',
975 format => 'pve-ipv4-config',
976 format_description => 'IPv4Format/CIDR',
977 description => 'IPv4 address in CIDR format.',
978 optional => 1,
979 default => 'dhcp',
980 },
981 gw => {
982 type => 'string',
983 format => 'ipv4',
984 format_description => 'GatewayIPv4',
985 description => 'Default gateway for IPv4 traffic.',
986 optional => 1,
987 requires => 'ip',
988 },
989 ip6 => {
990 type => 'string',
991 format => 'pve-ipv6-config',
992 format_description => 'IPv6Format/CIDR',
993 description => 'IPv6 address in CIDR format.',
994 optional => 1,
995 default => 'dhcp',
996 },
997 gw6 => {
998 type => 'string',
999 format => 'ipv6',
1000 format_description => 'GatewayIPv6',
1001 description => 'Default gateway for IPv6 traffic.',
1002 optional => 1,
1003 requires => 'ip6',
1004 },
1005};
1006PVE::JSONSchema::register_format('pve-qm-ipconfig', $ipconfig_fmt);
1007my $ipconfigdesc = {
1008 optional => 1,
1009 type => 'string', format => 'pve-qm-ipconfig',
1010 description => <<'EODESCR',
1011cloud-init: Specify IP addresses and gateways for the corresponding interface.
1012
1013IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
1014
4df98f2f
TL
1015The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit
1016gateway should be provided.
988be8d0
ML
1017For IPv6 the special string 'auto' can be used to use stateless autoconfiguration. This requires
1018cloud-init 19.4 or newer.
0c9a7596 1019
4df98f2f
TL
1020If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using
1021dhcp on IPv4.
0c9a7596
AD
1022EODESCR
1023};
1024PVE::JSONSchema::register_standard_option("pve-qm-ipconfig", $netdesc);
1025
1e3baf05
DM
1026for (my $i = 0; $i < $MAX_NETS; $i++) {
1027 $confdesc->{"net$i"} = $netdesc;
9ed7a77c
WB
1028 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
1029}
1030
1031foreach my $key (keys %$confdesc_cloudinit) {
1032 $confdesc->{$key} = $confdesc_cloudinit->{$key};
1e3baf05
DM
1033}
1034
83870398
DB
1035PVE::JSONSchema::register_format('pve-cpuset', \&pve_verify_cpuset);
1036sub pve_verify_cpuset {
1037 my ($set_text, $noerr) = @_;
1038
1039 my ($count, $members) = eval { PVE::CpuSet::parse_cpuset($set_text) };
1040
1041 if ($@) {
1042 return if $noerr;
1043 die "unable to parse cpuset option\n";
1044 }
1045
1046 return PVE::CpuSet->new($members)->short_string();
1047}
1048
ffa42b86
DC
1049PVE::JSONSchema::register_format('pve-volume-id-or-qm-path', \&verify_volume_id_or_qm_path);
1050sub verify_volume_id_or_qm_path {
822c8a07
WB
1051 my ($volid, $noerr) = @_;
1052
6e55f579
FE
1053 return $volid if $volid eq 'none' || $volid eq 'cdrom';
1054
1055 return verify_volume_id_or_absolute_path($volid, $noerr);
1056}
1057
1058PVE::JSONSchema::register_format('pve-volume-id-or-absolute-path', \&verify_volume_id_or_absolute_path);
1059sub verify_volume_id_or_absolute_path {
1060 my ($volid, $noerr) = @_;
1061
1062 return $volid if $volid =~ m|^/|;
ffa42b86 1063
822c8a07
WB
1064 $volid = eval { PVE::JSONSchema::check_format('pve-volume-id', $volid, '') };
1065 if ($@) {
d1c1af4b 1066 return if $noerr;
822c8a07
WB
1067 die $@;
1068 }
1069 return $volid;
1070}
1071
ff6ffe20 1072my $usb_fmt = {
a6b9aee4
DC
1073 host => {
1074 default_key => 1,
1075 type => 'string', format => 'pve-qm-usb-device',
1076 format_description => 'HOSTUSBDEVICE|spice',
52261945
DM
1077 description => <<EODESCR,
1078The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1079
1080 'bus-port(.port)*' (decimal numbers) or
1081 'vendor_id:product_id' (hexadeciaml numbers) or
1082 'spice'
1083
1084You can use the 'lsusb -t' command to list existing usb devices.
1085
4df98f2f
TL
1086NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1087machines - use with special care.
52261945
DM
1088
1089The value 'spice' can be used to add a usb redirection devices for spice.
1090EODESCR
a6b9aee4
DC
1091 },
1092 usb3 => {
1093 optional => 1,
1094 type => 'boolean',
97ef5356 1095 description => "Specifies whether if given host option is a USB3 device or port.",
52261945 1096 default => 0,
a6b9aee4
DC
1097 },
1098};
1099
1e3baf05
DM
1100my $usbdesc = {
1101 optional => 1,
ff6ffe20 1102 type => 'string', format => $usb_fmt,
52261945 1103 description => "Configure an USB device (n is 0 to 4).",
1e3baf05
DM
1104};
1105PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
1106
bae179aa
DA
1107my $serialdesc = {
1108 optional => 1,
ca0cef26 1109 type => 'string',
1b0b51ed 1110 pattern => '(/dev/.+|socket)',
52261945
DM
1111 description => "Create a serial device inside the VM (n is 0 to 3)",
1112 verbose_description => <<EODESCR,
52261945
DM
1113Create a serial device inside the VM (n is 0 to 3), and pass through a
1114host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1115host side (use 'qm terminal' to open a terminal connection).
bae179aa 1116
4df98f2f
TL
1117NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines -
1118use with special care.
bae179aa 1119
52261945 1120CAUTION: Experimental! User reported problems with this option.
bae179aa
DA
1121EODESCR
1122};
bae179aa 1123
1989a89c
DA
1124my $paralleldesc= {
1125 optional => 1,
ca0cef26 1126 type => 'string',
9ecc8431 1127 pattern => '/dev/parport\d+|/dev/usb/lp\d+',
52261945
DM
1128 description => "Map host parallel devices (n is 0 to 2).",
1129 verbose_description => <<EODESCR,
19672434 1130Map host parallel devices (n is 0 to 2).
1989a89c 1131
4df98f2f
TL
1132NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
1133machines - use with special care.
1989a89c 1134
52261945 1135CAUTION: Experimental! User reported problems with this option.
1989a89c
DA
1136EODESCR
1137};
1989a89c
DA
1138
1139for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1140 $confdesc->{"parallel$i"} = $paralleldesc;
1141}
1142
bae179aa
DA
1143for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1144 $confdesc->{"serial$i"} = $serialdesc;
1145}
1146
74c17b7a
SR
1147for (my $i = 0; $i < $PVE::QemuServer::PCI::MAX_HOSTPCI_DEVICES; $i++) {
1148 $confdesc->{"hostpci$i"} = $PVE::QemuServer::PCI::hostpcidesc;
040b06b7 1149}
1e3baf05 1150
e0fd2b2f
FE
1151for my $key (keys %{$PVE::QemuServer::Drive::drivedesc_hash}) {
1152 $confdesc->{$key} = $PVE::QemuServer::Drive::drivedesc_hash->{$key};
cdb0931f
DA
1153}
1154
1e3baf05
DM
1155for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1156 $confdesc->{"usb$i"} = $usbdesc;
1157}
1158
5cfa9f5f
SR
1159my $boot_fmt = {
1160 legacy => {
1161 optional => 1,
1162 default_key => 1,
1163 type => 'string',
1164 description => "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)."
1165 . " Deprecated, use 'order=' instead.",
1166 pattern => '[acdn]{1,4}',
1167 format_description => "[acdn]{1,4}",
1168
1169 # note: this is also the fallback if boot: is not given at all
1170 default => 'cdn',
1171 },
1172 order => {
1173 optional => 1,
1174 type => 'string',
1175 format => 'pve-qm-bootdev-list',
1176 format_description => "device[;device...]",
1177 description => <<EODESC,
1178The guest will attempt to boot from devices in the order they appear here.
1179
1180Disks, optical drives and passed-through storage USB devices will be directly
1181booted from, NICs will load PXE, and PCIe devices will either behave like disks
1182(e.g. NVMe) or load an option ROM (e.g. RAID controller, hardware NIC).
1183
1184Note that only devices in this list will be marked as bootable and thus loaded
1185by the guest firmware (BIOS/UEFI). If you require multiple disks for booting
1186(e.g. software-raid), you need to specify all of them here.
1187
1188Overrides the deprecated 'legacy=[acdn]*' value when given.
1189EODESC
1190 },
1191};
1192PVE::JSONSchema::register_format('pve-qm-boot', $boot_fmt);
1193
1194PVE::JSONSchema::register_format('pve-qm-bootdev', \&verify_bootdev);
1195sub verify_bootdev {
1196 my ($dev, $noerr) = @_;
1197
f9dde219
SR
1198 my $special = $dev =~ m/^efidisk/ || $dev =~ m/^tpmstate/;
1199 return $dev if PVE::QemuServer::Drive::is_valid_drivename($dev) && !$special;
5cfa9f5f
SR
1200
1201 my $check = sub {
1202 my ($base) = @_;
1203 return 0 if $dev !~ m/^$base\d+$/;
1204 return 0 if !$confdesc->{$dev};
1205 return 1;
1206 };
1207
1208 return $dev if $check->("net");
1209 return $dev if $check->("usb");
1210 return $dev if $check->("hostpci");
1211
d1c1af4b 1212 return if $noerr;
5cfa9f5f
SR
1213 die "invalid boot device '$dev'\n";
1214}
1215
1216sub print_bootorder {
1217 my ($devs) = @_;
4c27b18c 1218 return "" if !@$devs;
5cfa9f5f
SR
1219 my $data = { order => join(';', @$devs) };
1220 return PVE::JSONSchema::print_property_string($data, $boot_fmt);
1221}
1222
1e3baf05
DM
1223my $kvm_api_version = 0;
1224
1225sub kvm_version {
1e3baf05
DM
1226 return $kvm_api_version if $kvm_api_version;
1227
808a65b5 1228 open my $fh, '<', '/dev/kvm' or return;
1e3baf05 1229
646f2df4
WB
1230 # 0xae00 => KVM_GET_API_VERSION
1231 $kvm_api_version = ioctl($fh, 0xae00, 0);
808a65b5 1232 close($fh);
1e3baf05 1233
646f2df4 1234 return $kvm_api_version;
1e3baf05
DM
1235}
1236
1476b99f
DC
1237my $kvm_user_version = {};
1238my $kvm_mtime = {};
1e3baf05
DM
1239
1240sub kvm_user_version {
1476b99f 1241 my ($binary) = @_;
1e3baf05 1242
1476b99f
DC
1243 $binary //= get_command_for_arch(get_host_arch()); # get the native arch by default
1244 my $st = stat($binary);
1e3baf05 1245
1476b99f
DC
1246 my $cachedmtime = $kvm_mtime->{$binary} // -1;
1247 return $kvm_user_version->{$binary} if $kvm_user_version->{$binary} &&
1248 $cachedmtime == $st->mtime;
1249
1250 $kvm_user_version->{$binary} = 'unknown';
1251 $kvm_mtime->{$binary} = $st->mtime;
1e3baf05 1252
09b11429
TL
1253 my $code = sub {
1254 my $line = shift;
1255 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1476b99f 1256 $kvm_user_version->{$binary} = $2;
09b11429
TL
1257 }
1258 };
19672434 1259
1476b99f 1260 eval { run_command([$binary, '--version'], outfunc => $code); };
09b11429 1261 warn $@ if $@;
1e3baf05 1262
1476b99f 1263 return $kvm_user_version->{$binary};
1e3baf05
DM
1264
1265}
4df98f2f
TL
1266my sub extract_version {
1267 my ($machine_type, $version) = @_;
1268 $version = kvm_user_version() if !defined($version);
8eb73377 1269 return PVE::QemuServer::Machine::extract_version($machine_type, $version)
4df98f2f 1270}
1e3baf05 1271
db70021b
TL
1272sub kernel_has_vhost_net {
1273 return -c '/dev/vhost-net';
1274}
1e3baf05 1275
1e3baf05
DM
1276sub option_exists {
1277 my $key = shift;
1278 return defined($confdesc->{$key});
19672434 1279}
1e3baf05 1280
1e3baf05 1281my $cdrom_path;
1e3baf05
DM
1282sub get_cdrom_path {
1283
1284 return $cdrom_path if $cdrom_path;
1285
1286 return $cdrom_path = "/dev/cdrom" if -l "/dev/cdrom";
1287 return $cdrom_path = "/dev/cdrom1" if -l "/dev/cdrom1";
1288 return $cdrom_path = "/dev/cdrom2" if -l "/dev/cdrom2";
1289}
1290
1291sub get_iso_path {
1292 my ($storecfg, $vmid, $cdrom) = @_;
1293
1294 if ($cdrom eq 'cdrom') {
1295 return get_cdrom_path();
1296 } elsif ($cdrom eq 'none') {
1297 return '';
1298 } elsif ($cdrom =~ m|^/|) {
1299 return $cdrom;
1300 } else {
6b64503e 1301 return PVE::Storage::path($storecfg, $cdrom);
1e3baf05
DM
1302 }
1303}
1304
1305# try to convert old style file names to volume IDs
1306sub filename_to_volume_id {
1307 my ($vmid, $file, $media) = @_;
1308
0c9a7596 1309 if (!($file eq 'none' || $file eq 'cdrom' ||
1e3baf05 1310 $file =~ m|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
19672434 1311
d1c1af4b 1312 return if $file =~ m|/|;
19672434 1313
1e3baf05
DM
1314 if ($media && $media eq 'cdrom') {
1315 $file = "local:iso/$file";
1316 } else {
1317 $file = "local:$vmid/$file";
1318 }
1319 }
1320
1321 return $file;
1322}
1323
1324sub verify_media_type {
1325 my ($opt, $vtype, $media) = @_;
1326
1327 return if !$media;
1328
1329 my $etype;
1330 if ($media eq 'disk') {
a125592c 1331 $etype = 'images';
1e3baf05
DM
1332 } elsif ($media eq 'cdrom') {
1333 $etype = 'iso';
1334 } else {
1335 die "internal error";
1336 }
1337
1338 return if ($vtype eq $etype);
19672434 1339
1e3baf05
DM
1340 raise_param_exc({ $opt => "unexpected media type ($vtype != $etype)" });
1341}
1342
1343sub cleanup_drive_path {
1344 my ($opt, $storecfg, $drive) = @_;
1345
1346 # try to convert filesystem paths to volume IDs
1347
1348 if (($drive->{file} !~ m/^(cdrom|none)$/) &&
1349 ($drive->{file} !~ m|^/dev/.+|) &&
1350 ($drive->{file} !~ m/^([^:]+):(.+)$/) &&
19672434 1351 ($drive->{file} !~ m/^\d+$/)) {
1e3baf05 1352 my ($vtype, $volid) = PVE::Storage::path_to_volume_id($storecfg, $drive->{file});
4df98f2f
TL
1353 raise_param_exc({ $opt => "unable to associate path '$drive->{file}' to any storage"})
1354 if !$vtype;
1e3baf05
DM
1355 $drive->{media} = 'cdrom' if !$drive->{media} && $vtype eq 'iso';
1356 verify_media_type($opt, $vtype, $drive->{media});
1357 $drive->{file} = $volid;
1358 }
1359
1360 $drive->{media} = 'cdrom' if !$drive->{media} && $drive->{file} =~ m/^(cdrom|none)$/;
1361}
1362
b3c2bdd1
DM
1363sub parse_hotplug_features {
1364 my ($data) = @_;
1365
1366 my $res = {};
1367
1368 return $res if $data eq '0';
a1b7d579 1369
b3c2bdd1
DM
1370 $data = $confdesc->{hotplug}->{default} if $data eq '1';
1371
45827685 1372 foreach my $feature (PVE::Tools::split_list($data)) {
94ec5e7c 1373 if ($feature =~ m/^(network|disk|cpu|memory|usb|cloudinit)$/) {
b3c2bdd1
DM
1374 $res->{$1} = 1;
1375 } else {
596a0a20 1376 die "invalid hotplug feature '$feature'\n";
b3c2bdd1
DM
1377 }
1378 }
1379 return $res;
1380}
1381
1382PVE::JSONSchema::register_format('pve-hotplug-features', \&pve_verify_hotplug_features);
1383sub pve_verify_hotplug_features {
1384 my ($value, $noerr) = @_;
1385
1386 return $value if parse_hotplug_features($value);
1387
d1c1af4b 1388 return if $noerr;
b3c2bdd1
DM
1389
1390 die "unable to parse hotplug option\n";
1391}
1392
28ef82d3
DM
1393sub scsi_inquiry {
1394 my($fh, $noerr) = @_;
1395
1396 my $SG_IO = 0x2285;
1397 my $SG_GET_VERSION_NUM = 0x2282;
1398
1399 my $versionbuf = "\x00" x 8;
1400 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1401 if (!$ret) {
1402 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
d1c1af4b 1403 return;
28ef82d3 1404 }
97d62eb7 1405 my $version = unpack("I", $versionbuf);
28ef82d3
DM
1406 if ($version < 30000) {
1407 die "scsi generic interface too old\n" if !$noerr;
d1c1af4b 1408 return;
28ef82d3 1409 }
97d62eb7 1410
28ef82d3
DM
1411 my $buf = "\x00" x 36;
1412 my $sensebuf = "\x00" x 8;
f334aa3e 1413 my $cmd = pack("C x3 C x1", 0x12, 36);
97d62eb7 1414
28ef82d3
DM
1415 # see /usr/include/scsi/sg.h
1416 my $sg_io_hdr_t = "i i C C s I P P P I I i P C C C C S S i I I";
1417
f606d5bd
TL
1418 my $packet = pack(
1419 $sg_io_hdr_t, ord('S'), -3, length($cmd), length($sensebuf), 0, length($buf), $buf, $cmd, $sensebuf, 6000
1420 );
28ef82d3
DM
1421
1422 $ret = ioctl($fh, $SG_IO, $packet);
1423 if (!$ret) {
1424 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
d1c1af4b 1425 return;
28ef82d3 1426 }
97d62eb7 1427
28ef82d3
DM
1428 my @res = unpack($sg_io_hdr_t, $packet);
1429 if ($res[17] || $res[18]) {
1430 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
d1c1af4b 1431 return;
28ef82d3
DM
1432 }
1433
1434 my $res = {};
f606d5bd 1435 $res->@{qw(type removable vendor product revision)} = unpack("C C x6 A8 A16 A4", $buf);
28ef82d3 1436
f606d5bd
TL
1437 $res->{removable} = $res->{removable} & 128 ? 1 : 0;
1438 $res->{type} &= 0x1F;
09984754 1439
28ef82d3
DM
1440 return $res;
1441}
1442
1443sub path_is_scsi {
1444 my ($path) = @_;
1445
d1c1af4b 1446 my $fh = IO::File->new("+<$path") || return;
28ef82d3
DM
1447 my $res = scsi_inquiry($fh, 1);
1448 close($fh);
1449
1450 return $res;
1451}
1452
db656e5f 1453sub print_tabletdevice_full {
d559309f 1454 my ($conf, $arch) = @_;
b467f79a 1455
3392d6ca 1456 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
db656e5f
DM
1457
1458 # we use uhci for old VMs because tablet driver was buggy in older qemu
d559309f 1459 my $usbbus;
3392d6ca 1460 if (PVE::QemuServer::Machine::machine_type_is_q35($conf) || $arch eq 'aarch64') {
d559309f
WB
1461 $usbbus = 'ehci';
1462 } else {
1463 $usbbus = 'uhci';
1464 }
b467f79a 1465
db656e5f
DM
1466 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1467}
1468
d559309f 1469sub print_keyboarddevice_full {
6971c38e 1470 my ($conf, $arch) = @_;
d559309f 1471
d1c1af4b 1472 return if $arch ne 'aarch64';
d559309f
WB
1473
1474 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1475}
1476
a183df68
TL
1477my sub get_drive_id {
1478 my ($drive) = @_;
1479 return "$drive->{interface}$drive->{index}";
1480}
1481
ca916ecc 1482sub print_drivedevice_full {
d559309f 1483 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
ca916ecc
DA
1484
1485 my $device = '';
1486 my $maxdev = 0;
19672434 1487
a183df68 1488 my $drive_id = get_drive_id($drive);
ca916ecc 1489 if ($drive->{interface} eq 'virtio') {
4df98f2f
TL
1490 my $pciaddr = print_pci_addr("$drive_id", $bridges, $arch, $machine_type);
1491 $device = "virtio-blk-pci,drive=drive-$drive_id,id=${drive_id}${pciaddr}";
1492 $device .= ",iothread=iothread-$drive_id" if $drive->{iothread};
2ed36a41 1493 } elsif ($drive->{interface} eq 'scsi') {
6731a4cf 1494
ee034f5c 1495 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
2ed36a41
DM
1496 my $unit = $drive->{index} % $maxdev;
1497 my $devicetype = 'hd';
69bcf246
WB
1498 my $path = '';
1499 if (drive_is_cdrom($drive)) {
1500 $devicetype = 'cd';
29b19529 1501 } else {
69bcf246
WB
1502 if ($drive->{file} =~ m|^/|) {
1503 $path = $drive->{file};
1504 if (my $info = path_is_scsi($path)) {
8e3c33ab 1505 if ($info->{type} == 0 && $drive->{scsiblock}) {
69bcf246
WB
1506 $devicetype = 'block';
1507 } elsif ($info->{type} == 1) { # tape
1508 $devicetype = 'generic';
1509 }
1510 }
1511 } else {
1512 $path = PVE::Storage::path($storecfg, $drive->{file});
1513 }
1514
a034e3d6 1515 # for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
4df98f2f 1516 my $version = extract_version($machine_type, kvm_user_version());
a034e3d6 1517 if ($path =~ m/^iscsi\:\/\// &&
2ea5fb7e 1518 !min_version($version, 4, 1)) {
69bcf246
WB
1519 $devicetype = 'generic';
1520 }
1521 }
1522
ef88eaaa 1523 if (!$conf->{scsihw} || $conf->{scsihw} =~ m/^lsi/ || $conf->{scsihw} eq 'pvscsi') {
4df98f2f 1524 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit";
69bcf246 1525 } else {
4df98f2f
TL
1526 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0"
1527 .",lun=$drive->{index}";
69bcf246 1528 }
4df98f2f 1529 $device .= ",drive=drive-$drive_id,id=$drive_id";
cdd20088 1530
6c875f9f
NC
1531 if ($drive->{ssd} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1532 $device .= ",rotation_rate=1";
1533 }
e741c516 1534 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
6c875f9f
NC
1535
1536 } elsif ($drive->{interface} eq 'ide' || $drive->{interface} eq 'sata') {
e0fd2b2f 1537 my $maxdev = ($drive->{interface} eq 'sata') ? $PVE::QemuServer::Drive::MAX_SATA_DISKS : 2;
2ed36a41
DM
1538 my $controller = int($drive->{index} / $maxdev);
1539 my $unit = $drive->{index} % $maxdev;
1540 my $devicetype = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd";
1541
6c875f9f
NC
1542 $device = "ide-$devicetype";
1543 if ($drive->{interface} eq 'ide') {
1544 $device .= ",bus=ide.$controller,unit=$unit";
1545 } else {
1546 $device .= ",bus=ahci$controller.$unit";
1547 }
4df98f2f 1548 $device .= ",drive=drive-$drive_id,id=$drive_id";
6c875f9f
NC
1549
1550 if ($devicetype eq 'hd') {
1551 if (my $model = $drive->{model}) {
1552 $model = URI::Escape::uri_unescape($model);
1553 $device .= ",model=$model";
1554 }
1555 if ($drive->{ssd}) {
1556 $device .= ",rotation_rate=1";
1557 }
0f2812c2 1558 }
e741c516 1559 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
2ed36a41
DM
1560 } elsif ($drive->{interface} eq 'usb') {
1561 die "implement me";
1562 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1563 } else {
1564 die "unsupported interface type";
ca916ecc
DA
1565 }
1566
3b408e82
DM
1567 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex};
1568
a70e7e6c
TL
1569 if (my $serial = $drive->{serial}) {
1570 $serial = URI::Escape::uri_unescape($serial);
1571 $device .= ",serial=$serial";
1572 }
1573
1574
ca916ecc
DA
1575 return $device;
1576}
1577
15b21acc 1578sub get_initiator_name {
46f58b5f 1579 my $initiator;
15b21acc 1580
d1c1af4b 1581 my $fh = IO::File->new('/etc/iscsi/initiatorname.iscsi') || return;
46f58b5f
DM
1582 while (defined(my $line = <$fh>)) {
1583 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
15b21acc
MR
1584 $initiator = $1;
1585 last;
1586 }
46f58b5f
DM
1587 $fh->close();
1588
15b21acc
MR
1589 return $initiator;
1590}
1591
776c5f50 1592sub print_drive_commandline_full {
6d5673c3 1593 my ($storecfg, $vmid, $drive, $pbs_name, $io_uring) = @_;
1e3baf05 1594
d81f0f09
DM
1595 my $path;
1596 my $volid = $drive->{file};
5921764c 1597 my $format = $drive->{format};
a183df68 1598 my $drive_id = get_drive_id($drive);
370b05e7 1599
0fe779a6
WB
1600 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
1601 my $scfg = $storeid ? PVE::Storage::storage_config($storecfg, $storeid) : undef;
1602
d81f0f09
DM
1603 if (drive_is_cdrom($drive)) {
1604 $path = get_iso_path($storecfg, $vmid, $volid);
a183df68 1605 die "$drive_id: cannot back cdrom drive with PBS snapshot\n" if $pbs_name;
d81f0f09 1606 } else {
d81f0f09
DM
1607 if ($storeid) {
1608 $path = PVE::Storage::path($storecfg, $volid);
5921764c 1609 $format //= qemu_img_format($scfg, $volname);
d81f0f09
DM
1610 } else {
1611 $path = $volid;
5921764c 1612 $format //= "raw";
d81f0f09
DM
1613 }
1614 }
1615
5921764c
SR
1616 my $is_rbd = $path =~ m/^rbd:/;
1617
1e3baf05 1618 my $opts = '';
5921764c 1619 my @qemu_drive_options = qw(heads secs cyls trans media cache rerror werror aio discard);
1e3baf05 1620 foreach my $o (@qemu_drive_options) {
5fc74861 1621 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
19672434 1622 }
8a267708
DC
1623
1624 # snapshot only accepts on|off
1625 if (defined($drive->{snapshot})) {
1626 my $v = $drive->{snapshot} ? 'on' : 'off';
1627 $opts .= ",snapshot=$v";
1628 }
1629
1f91f7b4
TL
1630 if (defined($drive->{ro})) { # ro maps to QEMUs `readonly`, which accepts `on` or `off` only
1631 $opts .= ",readonly=" . ($drive->{ro} ? 'on' : 'off');
12e1d472
DC
1632 }
1633
fb8e95a2
WB
1634 foreach my $type (['', '-total'], [_rd => '-read'], [_wr => '-write']) {
1635 my ($dir, $qmpname) = @$type;
1636 if (my $v = $drive->{"mbps$dir"}) {
1637 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1638 }
1639 if (my $v = $drive->{"mbps${dir}_max"}) {
1640 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1641 }
1642 if (my $v = $drive->{"bps${dir}_max_length"}) {
1643 $opts .= ",throttling.bps$qmpname-max-length=$v";
1644 }
1645 if (my $v = $drive->{"iops${dir}"}) {
1646 $opts .= ",throttling.iops$qmpname=$v";
1647 }
1648 if (my $v = $drive->{"iops${dir}_max"}) {
8aca1654 1649 $opts .= ",throttling.iops$qmpname-max=$v";
fb8e95a2
WB
1650 }
1651 if (my $v = $drive->{"iops${dir}_max_length"}) {
8aca1654 1652 $opts .= ",throttling.iops$qmpname-max-length=$v";
fb8e95a2
WB
1653 }
1654 }
1655
5921764c
SR
1656 if ($pbs_name) {
1657 $format = "rbd" if $is_rbd;
a183df68
TL
1658 die "$drive_id: Proxmox Backup Server backed drive cannot auto-detect the format\n"
1659 if !$format;
5921764c
SR
1660 $opts .= ",format=alloc-track,file.driver=$format";
1661 } elsif ($format) {
1662 $opts .= ",format=$format";
1663 }
d81f0f09 1664
b2ee900e
WB
1665 my $cache_direct = 0;
1666
1667 if (my $cache = $drive->{cache}) {
1668 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
0fe779a6 1669 } elsif (!drive_is_cdrom($drive) && !($scfg && $scfg->{type} eq 'btrfs' && !$scfg->{nocow})) {
b2ee900e
WB
1670 $opts .= ",cache=none";
1671 $cache_direct = 1;
1672 }
1673
628937f5
SR
1674 # io_uring with cache mode writeback or writethrough on krbd will hang...
1675 my $rbd_no_io_uring = $scfg && $scfg->{type} eq 'rbd' && $scfg->{krbd} && !$cache_direct;
1676
78a3ada7
TL
1677 # io_uring with cache mode writeback or writethrough on LVM will hang, without cache only
1678 # sometimes, just plain disable...
1679 my $lvm_no_io_uring = $scfg && $scfg->{type} eq 'lvm';
ec5d198e 1680
e31762f2
FE
1681 # io_uring causes problems when used with CIFS since kernel 5.15
1682 # Some discussion: https://www.spinics.net/lists/linux-cifs/msg26734.html
1683 my $cifs_no_io_uring = $scfg && $scfg->{type} eq 'cifs';
1684
b2ee900e 1685 if (!$drive->{aio}) {
e31762f2 1686 if ($io_uring && !$rbd_no_io_uring && !$lvm_no_io_uring && !$cifs_no_io_uring) {
6d5673c3
SR
1687 # io_uring supports all cache modes
1688 $opts .= ",aio=io_uring";
b2ee900e 1689 } else {
6d5673c3
SR
1690 # aio native works only with O_DIRECT
1691 if($cache_direct) {
1692 $opts .= ",aio=native";
1693 } else {
1694 $opts .= ",aio=threads";
1695 }
b2ee900e
WB
1696 }
1697 }
11490cf2 1698
6e47c3b4
WB
1699 if (!drive_is_cdrom($drive)) {
1700 my $detectzeroes;
7d4e30f3 1701 if (defined($drive->{detect_zeroes}) && !$drive->{detect_zeroes}) {
6e47c3b4
WB
1702 $detectzeroes = 'off';
1703 } elsif ($drive->{discard}) {
1704 $detectzeroes = $drive->{discard} eq 'on' ? 'unmap' : 'on';
1705 } else {
1706 # This used to be our default with discard not being specified:
1707 $detectzeroes = 'on';
1708 }
5921764c
SR
1709
1710 # note: 'detect-zeroes' works per blockdev and we want it to persist
1711 # after the alloc-track is removed, so put it on 'file' directly
1712 my $dz_param = $pbs_name ? "file.detect-zeroes" : "detect-zeroes";
1713 $opts .= ",$dz_param=$detectzeroes" if $detectzeroes;
6e47c3b4 1714 }
f1e05305 1715
5921764c
SR
1716 if ($pbs_name) {
1717 $opts .= ",backing=$pbs_name";
1718 $opts .= ",auto-remove=on";
1719 }
1720
1721 # my $file_param = $pbs_name ? "file.file.filename" : "file";
1722 my $file_param = "file";
1723 if ($pbs_name) {
1724 # non-rbd drivers require the underlying file to be a seperate block
1725 # node, so add a second .file indirection
1726 $file_param .= ".file" if !$is_rbd;
1727 $file_param .= ".filename";
1728 }
1729 my $pathinfo = $path ? "$file_param=$path," : '';
1e3baf05 1730
3ebfcc86 1731 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1e3baf05
DM
1732}
1733
5921764c
SR
1734sub print_pbs_blockdev {
1735 my ($pbs_conf, $pbs_name) = @_;
1736 my $blockdev = "driver=pbs,node-name=$pbs_name,read-only=on";
1737 $blockdev .= ",repository=$pbs_conf->{repository}";
2dda626d 1738 $blockdev .= ",namespace=$pbs_conf->{namespace}" if $pbs_conf->{namespace};
5921764c
SR
1739 $blockdev .= ",snapshot=$pbs_conf->{snapshot}";
1740 $blockdev .= ",archive=$pbs_conf->{archive}";
1741 $blockdev .= ",keyfile=$pbs_conf->{keyfile}" if $pbs_conf->{keyfile};
1742 return $blockdev;
1743}
1744
cc4d6182 1745sub print_netdevice_full {
d559309f 1746 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
cc4d6182 1747
cc4d6182
DA
1748 my $device = $net->{model};
1749 if ($net->{model} eq 'virtio') {
1750 $device = 'virtio-net-pci';
1751 };
1752
d559309f 1753 my $pciaddr = print_pci_addr("$netid", $bridges, $arch, $machine_type);
5e2068d2 1754 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
a9410357 1755 if ($net->{queues} && $net->{queues} > 1 && $net->{model} eq 'virtio'){
4df98f2f
TL
1756 # Consider we have N queues, the number of vectors needed is 2 * N + 2, i.e., one per in
1757 # and out of each queue plus one config interrupt and control vector queue
a9410357
AD
1758 my $vectors = $net->{queues} * 2 + 2;
1759 $tmpstr .= ",vectors=$vectors,mq=on";
1760 }
cc4d6182 1761 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex} ;
ba9e1000 1762
0530177b
TL
1763 if (my $mtu = $net->{mtu}) {
1764 if ($net->{model} eq 'virtio' && $net->{bridge}) {
1765 my $bridge_mtu = PVE::Network::read_bridge_mtu($net->{bridge});
1766 if ($mtu == 1) {
1767 $mtu = $bridge_mtu;
1768 } elsif ($mtu < 576) {
1769 die "netdev $netid: MTU '$mtu' is smaller than the IP minimum MTU '576'\n";
1770 } elsif ($mtu > $bridge_mtu) {
1771 die "netdev $netid: MTU '$mtu' is bigger than the bridge MTU '$bridge_mtu'\n";
1772 }
1773 $tmpstr .= ",host_mtu=$mtu";
1774 } else {
1775 warn "WARN: netdev $netid: ignoring MTU '$mtu', not using VirtIO or no bridge configured.\n";
61a14cde 1776 }
61a14cde
AD
1777 }
1778
ba9e1000
DM
1779 if ($use_old_bios_files) {
1780 my $romfile;
1781 if ($device eq 'virtio-net-pci') {
1782 $romfile = 'pxe-virtio.rom';
1783 } elsif ($device eq 'e1000') {
1784 $romfile = 'pxe-e1000.rom';
e83dd50a
TL
1785 } elsif ($device eq 'e1000e') {
1786 $romfile = 'pxe-e1000e.rom';
ba9e1000
DM
1787 } elsif ($device eq 'ne2k') {
1788 $romfile = 'pxe-ne2k_pci.rom';
1789 } elsif ($device eq 'pcnet') {
1790 $romfile = 'pxe-pcnet.rom';
1791 } elsif ($device eq 'rtl8139') {
1792 $romfile = 'pxe-rtl8139.rom';
1793 }
1794 $tmpstr .= ",romfile=$romfile" if $romfile;
1795 }
1796
cc4d6182
DA
1797 return $tmpstr;
1798}
1799
1800sub print_netdev_full {
d559309f 1801 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
cc4d6182
DA
1802
1803 my $i = '';
1804 if ($netid =~ m/^net(\d+)$/) {
1805 $i = int($1);
1806 }
1807
1808 die "got strange net id '$i'\n" if $i >= ${MAX_NETS};
1809
1810 my $ifname = "tap${vmid}i$i";
1811
1812 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1813 die "interface name '$ifname' is too long (max 15 character)\n"
1814 if length($ifname) >= 16;
1815
1816 my $vhostparam = '';
6f0cb675 1817 if (is_native($arch)) {
db70021b 1818 $vhostparam = ',vhost=on' if kernel_has_vhost_net() && $net->{model} eq 'virtio';
6f0cb675 1819 }
cc4d6182
DA
1820
1821 my $vmname = $conf->{name} || "vm$vmid";
1822
a9410357 1823 my $netdev = "";
208ba94e 1824 my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
a9410357 1825
cc4d6182 1826 if ($net->{bridge}) {
4df98f2f
TL
1827 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script"
1828 .",downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
cc4d6182 1829 } else {
a9410357 1830 $netdev = "type=user,id=$netid,hostname=$vmname";
cc4d6182 1831 }
a9410357
AD
1832
1833 $netdev .= ",queues=$net->{queues}" if ($net->{queues} && $net->{model} eq 'virtio');
1834
1835 return $netdev;
cc4d6182 1836}
1e3baf05 1837
55655ebc
DC
1838my $vga_map = {
1839 'cirrus' => 'cirrus-vga',
1840 'std' => 'VGA',
1841 'vmware' => 'vmware-svga',
1842 'virtio' => 'virtio-vga',
6f070e39 1843 'virtio-gl' => 'virtio-vga-gl',
55655ebc
DC
1844};
1845
1846sub print_vga_device {
2ea5fb7e 1847 my ($conf, $vga, $arch, $machine_version, $machine, $id, $qxlnum, $bridges) = @_;
55655ebc
DC
1848
1849 my $type = $vga_map->{$vga->{type}};
86c9fafe 1850 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
d559309f
WB
1851 $type = 'virtio-gpu';
1852 }
55655ebc 1853 my $vgamem_mb = $vga->{memory};
6021c7a5
AL
1854
1855 my $max_outputs = '';
55655ebc
DC
1856 if ($qxlnum) {
1857 $type = $id ? 'qxl' : 'qxl-vga';
6021c7a5 1858
c5a4c92c 1859 if (!$conf->{ostype} || $conf->{ostype} =~ m/^(?:l\d\d)|(?:other)$/) {
6021c7a5 1860 # set max outputs so linux can have up to 4 qxl displays with one device
2ea5fb7e 1861 if (min_version($machine_version, 4, 1)) {
9e8976ea
TL
1862 $max_outputs = ",max_outputs=4";
1863 }
6021c7a5 1864 }
55655ebc 1865 }
6021c7a5 1866
55655ebc
DC
1867 die "no devicetype for $vga->{type}\n" if !$type;
1868
1869 my $memory = "";
1870 if ($vgamem_mb) {
6f070e39 1871 if ($vga->{type} =~ /^virtio/) {
55655ebc
DC
1872 my $bytes = PVE::Tools::convert_size($vgamem_mb, "mb" => "b");
1873 $memory = ",max_hostmem=$bytes";
1874 } elsif ($qxlnum) {
1875 # from https://www.spice-space.org/multiple-monitors.html
1876 $memory = ",vgamem_mb=$vga->{memory}";
1877 my $ram = $vgamem_mb * 4;
1878 my $vram = $vgamem_mb * 2;
1879 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
1880 } else {
1881 $memory = ",vgamem_mb=$vga->{memory}";
1882 }
1883 } elsif ($qxlnum && $id) {
1884 $memory = ",ram_size=67108864,vram_size=33554432";
1885 }
1886
789fe8e8
AL
1887 my $edidoff = "";
1888 if ($type eq 'VGA' && windows_version($conf->{ostype})) {
b5d32c6b 1889 $edidoff=",edid=off" if (!defined($conf->{bios}) || $conf->{bios} ne 'ovmf');
789fe8e8
AL
1890 }
1891
3392d6ca 1892 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
55655ebc
DC
1893 my $vgaid = "vga" . ($id // '');
1894 my $pciaddr;
1895 if ($q35 && $vgaid eq 'vga') {
daadd5a4 1896 # the first display uses pcie.0 bus on q35 machines
d559309f 1897 $pciaddr = print_pcie_addr($vgaid, $bridges, $arch, $machine);
55655ebc 1898 } else {
d559309f 1899 $pciaddr = print_pci_addr($vgaid, $bridges, $arch, $machine);
55655ebc
DC
1900 }
1901
9f979d9f 1902 if ($vga->{type} eq 'virtio-gl') {
8884a8bf
TL
1903 my $base = '/usr/lib/x86_64-linux-gnu/lib';
1904 die "missing libraries for '$vga->{type}' detected! Please install 'libgl1' and 'libegl1'\n"
1905 if !-e "${base}EGL.so.1" || !-e "${base}GL.so.1";
9f979d9f 1906
8884a8bf
TL
1907 die "no DRM render node detected (/dev/dri/renderD*), no GPU? - needed for '$vga->{type}' display\n"
1908 if !PVE::Tools::dir_glob_regex('/dev/dri/', "renderD.*");
9f979d9f
SI
1909 }
1910
789fe8e8 1911 return "$type,id=${vgaid}${memory}${max_outputs}${pciaddr}${edidoff}";
55655ebc
DC
1912}
1913
ffc0d8c7
WB
1914sub parse_number_sets {
1915 my ($set) = @_;
1916 my $res = [];
1917 foreach my $part (split(/;/, $set)) {
1918 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1919 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1920 push @$res, [ $1, $2 ];
2ed5d572 1921 } else {
ffc0d8c7 1922 die "invalid range: $part\n";
2ed5d572
AD
1923 }
1924 }
ffc0d8c7
WB
1925 return $res;
1926}
2ed5d572 1927
ffc0d8c7
WB
1928sub parse_numa {
1929 my ($data) = @_;
1930
4df98f2f 1931 my $res = parse_property_string($numa_fmt, $data);
ffc0d8c7
WB
1932 $res->{cpus} = parse_number_sets($res->{cpus}) if defined($res->{cpus});
1933 $res->{hostnodes} = parse_number_sets($res->{hostnodes}) if defined($res->{hostnodes});
2ed5d572
AD
1934 return $res;
1935}
1936
1e3baf05
DM
1937# netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1938sub parse_net {
1939 my ($data) = @_;
1940
4df98f2f 1941 my $res = eval { parse_property_string($net_fmt, $data) };
cd9c34d1
WB
1942 if ($@) {
1943 warn $@;
d1c1af4b 1944 return;
1e3baf05 1945 }
b5b99790
WB
1946 if (!defined($res->{macaddr})) {
1947 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
1948 $res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
1949 }
0c9a7596
AD
1950 return $res;
1951}
1952
1953# ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1954sub parse_ipconfig {
1955 my ($data) = @_;
1956
4df98f2f 1957 my $res = eval { parse_property_string($ipconfig_fmt, $data) };
0c9a7596
AD
1958 if ($@) {
1959 warn $@;
d1c1af4b 1960 return;
0c9a7596
AD
1961 }
1962
1963 if ($res->{gw} && !$res->{ip}) {
1964 warn 'gateway specified without specifying an IP address';
d1c1af4b 1965 return;
0c9a7596
AD
1966 }
1967 if ($res->{gw6} && !$res->{ip6}) {
1968 warn 'IPv6 gateway specified without specifying an IPv6 address';
d1c1af4b 1969 return;
0c9a7596
AD
1970 }
1971 if ($res->{gw} && $res->{ip} eq 'dhcp') {
1972 warn 'gateway specified together with DHCP';
d1c1af4b 1973 return;
0c9a7596
AD
1974 }
1975 if ($res->{gw6} && $res->{ip6} !~ /^$IPV6RE/) {
1976 # gw6 + auto/dhcp
1977 warn "IPv6 gateway specified together with $res->{ip6} address";
d1c1af4b 1978 return;
0c9a7596
AD
1979 }
1980
1981 if (!$res->{ip} && !$res->{ip6}) {
1982 return { ip => 'dhcp', ip6 => 'dhcp' };
1983 }
1984
1e3baf05
DM
1985 return $res;
1986}
1987
1988sub print_net {
1989 my $net = shift;
1990
cd9c34d1 1991 return PVE::JSONSchema::print_property_string($net, $net_fmt);
1e3baf05
DM
1992}
1993
1994sub add_random_macs {
1995 my ($settings) = @_;
1996
1997 foreach my $opt (keys %$settings) {
1998 next if $opt !~ m/^net(\d+)$/;
1999 my $net = parse_net($settings->{$opt});
2000 next if !$net;
2001 $settings->{$opt} = print_net($net);
2002 }
2003}
2004
055d554d
DM
2005sub vm_is_volid_owner {
2006 my ($storecfg, $vmid, $volid) = @_;
2007
2008 if ($volid !~ m|^/|) {
2009 my ($path, $owner);
2010 eval { ($path, $owner) = PVE::Storage::path($storecfg, $volid); };
2011 if ($owner && ($owner == $vmid)) {
2012 return 1;
2013 }
2014 }
2015
d1c1af4b 2016 return;
055d554d
DM
2017}
2018
055d554d
DM
2019sub vmconfig_register_unused_drive {
2020 my ($storecfg, $vmid, $conf, $drive) = @_;
2021
2d9ddec5
WB
2022 if (drive_is_cloudinit($drive)) {
2023 eval { PVE::Storage::vdisk_free($storecfg, $drive->{file}) };
2024 warn $@ if $@;
95a5135d 2025 delete $conf->{cloudinit};
2d9ddec5 2026 } elsif (!drive_is_cdrom($drive)) {
055d554d
DM
2027 my $volid = $drive->{file};
2028 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
8793d495 2029 PVE::QemuConfig->add_unused_volume($conf, $volid, $vmid);
055d554d
DM
2030 }
2031 }
2032}
2033
1f30ac3a 2034# smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
ff6ffe20 2035my $smbios1_fmt = {
bd27e851
WB
2036 uuid => {
2037 type => 'string',
2038 pattern => '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2039 format_description => 'UUID',
52261945 2040 description => "Set SMBIOS1 UUID.",
bd27e851
WB
2041 optional => 1,
2042 },
2043 version => {
2044 type => 'string',
1f30ac3a
CE
2045 pattern => '[A-Za-z0-9+\/]+={0,2}',
2046 format_description => 'Base64 encoded string',
52261945 2047 description => "Set SMBIOS1 version.",
bd27e851
WB
2048 optional => 1,
2049 },
2050 serial => {
2051 type => 'string',
1f30ac3a
CE
2052 pattern => '[A-Za-z0-9+\/]+={0,2}',
2053 format_description => 'Base64 encoded string',
52261945 2054 description => "Set SMBIOS1 serial number.",
bd27e851
WB
2055 optional => 1,
2056 },
2057 manufacturer => {
2058 type => 'string',
1f30ac3a
CE
2059 pattern => '[A-Za-z0-9+\/]+={0,2}',
2060 format_description => 'Base64 encoded string',
52261945 2061 description => "Set SMBIOS1 manufacturer.",
bd27e851
WB
2062 optional => 1,
2063 },
2064 product => {
2065 type => 'string',
1f30ac3a
CE
2066 pattern => '[A-Za-z0-9+\/]+={0,2}',
2067 format_description => 'Base64 encoded string',
52261945 2068 description => "Set SMBIOS1 product ID.",
bd27e851
WB
2069 optional => 1,
2070 },
2071 sku => {
2072 type => 'string',
1f30ac3a
CE
2073 pattern => '[A-Za-z0-9+\/]+={0,2}',
2074 format_description => 'Base64 encoded string',
52261945 2075 description => "Set SMBIOS1 SKU string.",
bd27e851
WB
2076 optional => 1,
2077 },
2078 family => {
2079 type => 'string',
1f30ac3a
CE
2080 pattern => '[A-Za-z0-9+\/]+={0,2}',
2081 format_description => 'Base64 encoded string',
52261945 2082 description => "Set SMBIOS1 family string.",
bd27e851
WB
2083 optional => 1,
2084 },
1f30ac3a
CE
2085 base64 => {
2086 type => 'boolean',
2087 description => 'Flag to indicate that the SMBIOS values are base64 encoded',
2088 optional => 1,
2089 },
2796e7d5
DM
2090};
2091
2796e7d5
DM
2092sub parse_smbios1 {
2093 my ($data) = @_;
2094
4df98f2f 2095 my $res = eval { parse_property_string($smbios1_fmt, $data) };
bd27e851 2096 warn $@ if $@;
2796e7d5
DM
2097 return $res;
2098}
2099
cd11416f
DM
2100sub print_smbios1 {
2101 my ($smbios1) = @_;
ff6ffe20 2102 return PVE::JSONSchema::print_property_string($smbios1, $smbios1_fmt);
cd11416f
DM
2103}
2104
ff6ffe20 2105PVE::JSONSchema::register_format('pve-qm-smbios1', $smbios1_fmt);
2796e7d5 2106
0ea9541d
DM
2107sub parse_watchdog {
2108 my ($value) = @_;
2109
d1c1af4b 2110 return if !$value;
0ea9541d 2111
4df98f2f 2112 my $res = eval { parse_property_string($watchdog_fmt, $value) };
ec3582b5 2113 warn $@ if $@;
0ea9541d
DM
2114 return $res;
2115}
2116
9d66b397 2117sub parse_guest_agent {
a2af1bbe 2118 my ($conf) = @_;
9d66b397 2119
a2af1bbe 2120 return {} if !defined($conf->{agent});
9d66b397 2121
a2af1bbe 2122 my $res = eval { parse_property_string($agent_fmt, $conf->{agent}) };
9d66b397
SI
2123 warn $@ if $@;
2124
2125 # if the agent is disabled ignore the other potentially set properties
2126 return {} if !$res->{enabled};
2127 return $res;
2128}
2129
a2af1bbe
TL
2130sub get_qga_key {
2131 my ($conf, $key) = @_;
2132 return undef if !defined($conf->{agent});
2133
2134 my $agent = parse_guest_agent($conf);
2135 return $agent->{$key};
2136}
2137
55655ebc
DC
2138sub parse_vga {
2139 my ($value) = @_;
2140
2141 return {} if !$value;
4df98f2f 2142 my $res = eval { parse_property_string($vga_fmt, $value) };
55655ebc
DC
2143 warn $@ if $@;
2144 return $res;
2145}
2146
2cf61f33
SR
2147sub parse_rng {
2148 my ($value) = @_;
2149
d1c1af4b 2150 return if !$value;
2cf61f33 2151
4df98f2f 2152 my $res = eval { parse_property_string($rng_fmt, $value) };
2cf61f33
SR
2153 warn $@ if $@;
2154 return $res;
2155}
2156
26b443c8
TL
2157sub parse_meta_info {
2158 my ($value) = @_;
2159
2160 return if !$value;
2161
2162 my $res = eval { parse_property_string($meta_info_fmt, $value) };
2163 warn $@ if $@;
2164 return $res;
2165}
2166
2167sub new_meta_info_string {
2168 my () = @_; # for now do not allow to override any value
2169
2170 return PVE::JSONSchema::print_property_string(
2171 {
af2a1a1c 2172 'creation-qemu' => kvm_user_version(),
26b443c8
TL
2173 ctime => "". int(time()),
2174 },
2175 $meta_info_fmt
2176 );
2177}
2178
cc181036
TL
2179sub qemu_created_version_fixups {
2180 my ($conf, $forcemachine, $kvmver) = @_;
2181
2182 my $meta = parse_meta_info($conf->{meta}) // {};
2183 my $forced_vers = PVE::QemuServer::Machine::extract_version($forcemachine);
2184
2185 # check if we need to apply some handling for VMs that always use the latest machine version but
2186 # had a machine version transition happen that affected HW such that, e.g., an OS config change
2187 # would be required (we do not want to pin machine version for non-windows OS type)
2188 if (
2189 (!defined($conf->{machine}) || $conf->{machine} =~ m/^(?:pc|q35|virt)$/) # non-versioned machine
2190 && (!defined($meta->{'creation-qemu'}) || !min_version($meta->{'creation-qemu'}, 6, 1)) # created before 6.1
2191 && (!$forced_vers || min_version($forced_vers, 6, 1)) # handle snapshot-rollback/migrations
2192 && min_version($kvmver, 6, 1) # only need to apply the change since 6.1
2193 ) {
2194 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
2195 if ($q35 && $conf->{ostype} && $conf->{ostype} eq 'l26') {
2196 # this changed to default-on in Q 6.1 for q35 machines, it will mess with PCI slot view
2197 # and thus with the predictable interface naming of systemd
2198 return ['-global', 'ICH9-LPC.acpi-pci-hotplug-with-bridge-support=off'];
2199 }
2200 }
2201 return;
2202}
2203
1e3baf05
DM
2204PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
2205sub verify_usb_device {
2206 my ($value, $noerr) = @_;
2207
2208 return $value if parse_usb_device($value);
2209
d1c1af4b 2210 return if $noerr;
19672434 2211
1e3baf05
DM
2212 die "unable to parse usb device\n";
2213}
2214
1e3baf05
DM
2215# add JSON properties for create and set function
2216sub json_config_properties {
c1accf9d 2217 my ($prop, $with_disk_alloc) = @_;
1e3baf05 2218
5a08fb9c
TL
2219 my $skip_json_config_opts = {
2220 parent => 1,
2221 snaptime => 1,
2222 vmstate => 1,
2223 runningmachine => 1,
2224 runningcpu => 1,
26b443c8 2225 meta => 1,
5a08fb9c
TL
2226 };
2227
1e3baf05 2228 foreach my $opt (keys %$confdesc) {
5a08fb9c 2229 next if $skip_json_config_opts->{$opt};
c1accf9d
FE
2230
2231 if ($with_disk_alloc && is_valid_drivename($opt)) {
2232 $prop->{$opt} = $PVE::QemuServer::Drive::drivedesc_hash_with_alloc->{$opt};
2233 } else {
2234 $prop->{$opt} = $confdesc->{$opt};
2235 }
1e3baf05
DM
2236 }
2237
2238 return $prop;
2239}
2240
39051ac0
FE
2241# Properties that we can read from an OVF file
2242sub json_ovf_properties {
2243 my $prop = {};
2244
2245 for my $device (PVE::QemuServer::Drive::valid_drive_names()) {
2246 $prop->{$device} = {
2247 type => 'string',
2248 format => 'pve-volume-id-or-absolute-path',
2249 description => "Disk image that gets imported to $device",
2250 optional => 1,
2251 };
2252 }
2253
2254 $prop->{cores} = {
2255 type => 'integer',
2256 description => "The number of CPU cores.",
2257 optional => 1,
2258 };
2259 $prop->{memory} = {
2260 type => 'integer',
2261 description => "Amount of RAM for the VM in MB.",
2262 optional => 1,
2263 };
2264 $prop->{name} = {
2265 type => 'string',
2266 description => "Name of the VM.",
2267 optional => 1,
2268 };
2269
2270 return $prop;
2271}
2272
d41121fd
DM
2273# return copy of $confdesc_cloudinit to generate documentation
2274sub cloudinit_config_properties {
2275
2276 return dclone($confdesc_cloudinit);
2277}
2278
1e3baf05
DM
2279sub check_type {
2280 my ($key, $value) = @_;
2281
2282 die "unknown setting '$key'\n" if !$confdesc->{$key};
2283
2284 my $type = $confdesc->{$key}->{type};
2285
6b64503e 2286 if (!defined($value)) {
1e3baf05
DM
2287 die "got undefined value\n";
2288 }
2289
2290 if ($value =~ m/[\n\r]/) {
2291 die "property contains a line feed\n";
2292 }
2293
2294 if ($type eq 'boolean') {
19672434
DM
2295 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2296 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2297 die "type check ('boolean') failed - got '$value'\n";
1e3baf05
DM
2298 } elsif ($type eq 'integer') {
2299 return int($1) if $value =~ m/^(\d+)$/;
2300 die "type check ('integer') failed - got '$value'\n";
04432191
AD
2301 } elsif ($type eq 'number') {
2302 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2303 die "type check ('number') failed - got '$value'\n";
1e3baf05
DM
2304 } elsif ($type eq 'string') {
2305 if (my $fmt = $confdesc->{$key}->{format}) {
1e3baf05 2306 PVE::JSONSchema::check_format($fmt, $value);
19672434
DM
2307 return $value;
2308 }
1e3baf05 2309 $value =~ s/^\"(.*)\"$/$1/;
19672434 2310 return $value;
1e3baf05
DM
2311 } else {
2312 die "internal error"
2313 }
2314}
2315
1e3baf05 2316sub destroy_vm {
75854662 2317 my ($storecfg, $vmid, $skiplock, $replacement_conf, $purge_unreferenced) = @_;
1e3baf05 2318
ffda963f 2319 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 2320
ffda963f 2321 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 2322
5e67a2d2
DC
2323 if ($conf->{template}) {
2324 # check if any base image is still used by a linked clone
3ab0f925 2325 PVE::QemuConfig->foreach_volume_full($conf, { include_unused => 1 }, sub {
5e67a2d2 2326 my ($ds, $drive) = @_;
5e67a2d2
DC
2327 return if drive_is_cdrom($drive);
2328
2329 my $volid = $drive->{file};
5e67a2d2
DC
2330 return if !$volid || $volid =~ m|^/|;
2331
2332 die "base volume '$volid' is still in use by linked cloned\n"
2333 if PVE::Storage::volume_is_base_and_used($storecfg, $volid);
2334
2335 });
2336 }
2337
3e07c6d5 2338 my $volids = {};
ba1a1984 2339 my $remove_owned_drive = sub {
1e3baf05 2340 my ($ds, $drive) = @_;
9c52f5ed 2341 return if drive_is_cdrom($drive, 1);
1e3baf05
DM
2342
2343 my $volid = $drive->{file};
ff1a2432 2344 return if !$volid || $volid =~ m|^/|;
3e07c6d5 2345 return if $volids->{$volid};
1e3baf05 2346
6b64503e 2347 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
ff1a2432 2348 return if !$path || !$owner || ($owner != $vmid);
1e3baf05 2349
3e07c6d5 2350 $volids->{$volid} = 1;
a2f50f01 2351 eval { PVE::Storage::vdisk_free($storecfg, $volid) };
31b52247 2352 warn "Could not remove disk '$volid', check manually: $@" if $@;
ba1a1984
FE
2353 };
2354
2355 # only remove disks owned by this VM (referenced in the config)
2356 my $include_opts = {
2357 include_unused => 1,
2358 extra_keys => ['vmstate'],
2359 };
2360 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $remove_owned_drive);
2361
2362 for my $snap (values %{$conf->{snapshots}}) {
2363 next if !defined($snap->{vmstate});
2364 my $drive = PVE::QemuConfig->parse_volume('vmstate', $snap->{vmstate}, 1);
2365 next if !defined($drive);
2366 $remove_owned_drive->('vmstate', $drive);
2367 }
19672434 2368
3e07c6d5
FG
2369 PVE::QemuConfig->foreach_volume_full($conf->{pending}, $include_opts, $remove_owned_drive);
2370
75854662 2371 if ($purge_unreferenced) { # also remove unreferenced disk
d0ff75d9 2372 my $vmdisks = PVE::Storage::vdisk_list($storecfg, undef, $vmid, undef, 'images');
75854662
TL
2373 PVE::Storage::foreach_volid($vmdisks, sub {
2374 my ($volid, $sid, $volname, $d) = @_;
2375 eval { PVE::Storage::vdisk_free($storecfg, $volid) };
2376 warn $@ if $@;
2377 });
2378 }
dfda979e 2379
b04ea584 2380 if (defined $replacement_conf) {
8baf8bc7 2381 PVE::QemuConfig->write_config($vmid, $replacement_conf);
dfda979e
DJ
2382 } else {
2383 PVE::QemuConfig->destroy_config($vmid);
2384 }
1e3baf05
DM
2385}
2386
1e3baf05 2387sub parse_vm_config {
ad5812d8 2388 my ($filename, $raw, $strict) = @_;
1e3baf05 2389
d1c1af4b 2390 return if !defined($raw);
1e3baf05 2391
554ac7e7 2392 my $res = {
fc1ddcdc 2393 digest => Digest::SHA::sha1_hex($raw),
0d18dcfc 2394 snapshots => {},
0d732d16 2395 pending => {},
95a5135d 2396 cloudinit => {},
554ac7e7 2397 };
1e3baf05 2398
ad5812d8
FG
2399 my $handle_error = sub {
2400 my ($msg) = @_;
2401
2402 if ($strict) {
2403 die $msg;
2404 } else {
2405 warn $msg;
2406 }
2407 };
2408
19672434 2409 $filename =~ m|/qemu-server/(\d+)\.conf$|
1e3baf05
DM
2410 || die "got strange filename '$filename'";
2411
2412 my $vmid = $1;
2413
0d18dcfc 2414 my $conf = $res;
b0ec896e 2415 my $descr;
e297c490 2416 my $section = '';
0581fe4f 2417
0d18dcfc
DM
2418 my @lines = split(/\n/, $raw);
2419 foreach my $line (@lines) {
1e3baf05 2420 next if $line =~ m/^\s*$/;
be190583 2421
eab09f4e 2422 if ($line =~ m/^\[PENDING\]\s*$/i) {
e297c490 2423 $section = 'pending';
b0ec896e
DM
2424 if (defined($descr)) {
2425 $descr =~ s/\s+$//;
2426 $conf->{description} = $descr;
2427 }
2428 $descr = undef;
e297c490 2429 $conf = $res->{$section} = {};
eab09f4e 2430 next;
95a5135d
AD
2431 } elsif ($line =~ m/^\[special:cloudinit\]\s*$/i) {
2432 $section = 'cloudinit';
2433 $descr = undef;
2434 $conf = $res->{$section} = {};
2435 next;
eab09f4e 2436
0d732d16 2437 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
e297c490 2438 $section = $1;
b0ec896e
DM
2439 if (defined($descr)) {
2440 $descr =~ s/\s+$//;
2441 $conf->{description} = $descr;
2442 }
2443 $descr = undef;
e297c490 2444 $conf = $res->{snapshots}->{$section} = {};
0d18dcfc
DM
2445 next;
2446 }
1e3baf05 2447
d1e7b922 2448 if ($line =~ m/^\#(.*)$/) {
b0ec896e 2449 $descr = '' if !defined($descr);
0581fe4f
DM
2450 $descr .= PVE::Tools::decode_text($1) . "\n";
2451 next;
2452 }
2453
1e3baf05 2454 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
b0ec896e 2455 $descr = '' if !defined($descr);
0581fe4f 2456 $descr .= PVE::Tools::decode_text($2);
0d18dcfc
DM
2457 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2458 $conf->{snapstate} = $1;
1e3baf05
DM
2459 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2460 my $key = $1;
2461 my $value = $2;
0d18dcfc 2462 $conf->{$key} = $value;
ef824322 2463 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
e297c490 2464 my $value = $1;
ef824322
DM
2465 if ($section eq 'pending') {
2466 $conf->{delete} = $value; # we parse this later
2467 } else {
ad5812d8 2468 $handle_error->("vm $vmid - property 'delete' is only allowed in [PENDING]\n");
eab09f4e 2469 }
15cf7698 2470 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
1e3baf05
DM
2471 my $key = $1;
2472 my $value = $2;
2473 eval { $value = check_type($key, $value); };
2474 if ($@) {
ad5812d8 2475 $handle_error->("vm $vmid - unable to parse value of '$key' - $@");
1e3baf05 2476 } else {
b799312f 2477 $key = 'ide2' if $key eq 'cdrom';
1e3baf05 2478 my $fmt = $confdesc->{$key}->{format};
b799312f 2479 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
1e3baf05
DM
2480 my $v = parse_drive($key, $value);
2481 if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) {
2482 $v->{file} = $volid;
71c58bb7 2483 $value = print_drive($v);
1e3baf05 2484 } else {
ad5812d8 2485 $handle_error->("vm $vmid - unable to parse value of '$key'\n");
1e3baf05
DM
2486 next;
2487 }
2488 }
2489
b799312f 2490 $conf->{$key} = $value;
1e3baf05 2491 }
f8d2a1ce 2492 } else {
ad5812d8 2493 $handle_error->("vm $vmid - unable to parse config: $line\n");
1e3baf05
DM
2494 }
2495 }
2496
b0ec896e
DM
2497 if (defined($descr)) {
2498 $descr =~ s/\s+$//;
2499 $conf->{description} = $descr;
2500 }
0d18dcfc 2501 delete $res->{snapstate}; # just to be sure
1e3baf05
DM
2502
2503 return $res;
2504}
2505
1858638f
DM
2506sub write_vm_config {
2507 my ($filename, $conf) = @_;
1e3baf05 2508
0d18dcfc
DM
2509 delete $conf->{snapstate}; # just to be sure
2510
1858638f
DM
2511 if ($conf->{cdrom}) {
2512 die "option ide2 conflicts with cdrom\n" if $conf->{ide2};
2513 $conf->{ide2} = $conf->{cdrom};
2514 delete $conf->{cdrom};
2515 }
1e3baf05
DM
2516
2517 # we do not use 'smp' any longer
1858638f
DM
2518 if ($conf->{sockets}) {
2519 delete $conf->{smp};
2520 } elsif ($conf->{smp}) {
2521 $conf->{sockets} = $conf->{smp};
2522 delete $conf->{cores};
2523 delete $conf->{smp};
1e3baf05
DM
2524 }
2525
ee2f90b1 2526 my $used_volids = {};
0d18dcfc 2527
ee2f90b1 2528 my $cleanup_config = sub {
ef824322 2529 my ($cref, $pending, $snapname) = @_;
1858638f 2530
ee2f90b1
DM
2531 foreach my $key (keys %$cref) {
2532 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
95a5135d 2533 $key eq 'snapstate' || $key eq 'pending' || $key eq 'cloudinit';
ee2f90b1 2534 my $value = $cref->{$key};
ef824322
DM
2535 if ($key eq 'delete') {
2536 die "propertry 'delete' is only allowed in [PENDING]\n"
2537 if !$pending;
2538 # fixme: check syntax?
2539 next;
2540 }
ee2f90b1
DM
2541 eval { $value = check_type($key, $value); };
2542 die "unable to parse value of '$key' - $@" if $@;
1858638f 2543
ee2f90b1
DM
2544 $cref->{$key} = $value;
2545
74479ee9 2546 if (!$snapname && is_valid_drivename($key)) {
ed221350 2547 my $drive = parse_drive($key, $value);
ee2f90b1
DM
2548 $used_volids->{$drive->{file}} = 1 if $drive && $drive->{file};
2549 }
1e3baf05 2550 }
ee2f90b1
DM
2551 };
2552
2553 &$cleanup_config($conf);
ef824322
DM
2554
2555 &$cleanup_config($conf->{pending}, 1);
2556
95a5135d
AD
2557 &$cleanup_config($conf->{cloudinit});
2558
ee2f90b1 2559 foreach my $snapname (keys %{$conf->{snapshots}}) {
15c6e277 2560 die "internal error: snapshot name '$snapname' is forbidden" if lc($snapname) eq 'pending';
ef824322 2561 &$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname);
1e3baf05
DM
2562 }
2563
1858638f
DM
2564 # remove 'unusedX' settings if we re-add a volume
2565 foreach my $key (keys %$conf) {
2566 my $value = $conf->{$key};
ee2f90b1 2567 if ($key =~ m/^unused/ && $used_volids->{$value}) {
1858638f 2568 delete $conf->{$key};
1e3baf05 2569 }
1858638f 2570 }
be190583 2571
0d18dcfc 2572 my $generate_raw_config = sub {
b0ec896e 2573 my ($conf, $pending) = @_;
0581fe4f 2574
0d18dcfc
DM
2575 my $raw = '';
2576
2577 # add description as comment to top of file
b0ec896e
DM
2578 if (defined(my $descr = $conf->{description})) {
2579 if ($descr) {
2580 foreach my $cl (split(/\n/, $descr)) {
2581 $raw .= '#' . PVE::Tools::encode_text($cl) . "\n";
2582 }
2583 } else {
2584 $raw .= "#\n" if $pending;
2585 }
0d18dcfc
DM
2586 }
2587
2588 foreach my $key (sort keys %$conf) {
95a5135d 2589 next if $key =~ /^(digest|description|pending|cloudinit|snapshots)$/;
0d18dcfc
DM
2590 $raw .= "$key: $conf->{$key}\n";
2591 }
2592 return $raw;
2593 };
0581fe4f 2594
0d18dcfc 2595 my $raw = &$generate_raw_config($conf);
ef824322
DM
2596
2597 if (scalar(keys %{$conf->{pending}})){
2598 $raw .= "\n[PENDING]\n";
b0ec896e 2599 $raw .= &$generate_raw_config($conf->{pending}, 1);
ef824322
DM
2600 }
2601
95a5135d
AD
2602 if (scalar(keys %{$conf->{cloudinit}})){
2603 $raw .= "\n[special:cloudinit]\n";
2604 $raw .= &$generate_raw_config($conf->{cloudinit});
2605 }
2606
0d18dcfc
DM
2607 foreach my $snapname (sort keys %{$conf->{snapshots}}) {
2608 $raw .= "\n[$snapname]\n";
2609 $raw .= &$generate_raw_config($conf->{snapshots}->{$snapname});
1858638f 2610 }
1e3baf05 2611
1858638f
DM
2612 return $raw;
2613}
1e3baf05 2614
19672434 2615sub load_defaults {
1e3baf05
DM
2616
2617 my $res = {};
2618
2619 # we use static defaults from our JSON schema configuration
2620 foreach my $key (keys %$confdesc) {
2621 if (defined(my $default = $confdesc->{$key}->{default})) {
2622 $res->{$key} = $default;
2623 }
2624 }
19672434 2625
1e3baf05
DM
2626 return $res;
2627}
2628
2629sub config_list {
2630 my $vmlist = PVE::Cluster::get_vmlist();
2631 my $res = {};
2632 return $res if !$vmlist || !$vmlist->{ids};
2633 my $ids = $vmlist->{ids};
38277afc 2634 my $nodename = nodename();
1e3baf05 2635
1e3baf05
DM
2636 foreach my $vmid (keys %$ids) {
2637 my $d = $ids->{$vmid};
2638 next if !$d->{node} || $d->{node} ne $nodename;
5ee957cc 2639 next if !$d->{type} || $d->{type} ne 'qemu';
1e3baf05
DM
2640 $res->{$vmid}->{exists} = 1;
2641 }
2642 return $res;
2643}
2644
64e13401
DM
2645# test if VM uses local resources (to prevent migration)
2646sub check_local_resources {
2647 my ($conf, $noerr) = @_;
2648
ca6abacf 2649 my @loc_res = ();
19672434 2650
ca6abacf
TM
2651 push @loc_res, "hostusb" if $conf->{hostusb}; # old syntax
2652 push @loc_res, "hostpci" if $conf->{hostpci}; # old syntax
64e13401 2653
ca6abacf 2654 push @loc_res, "ivshmem" if $conf->{ivshmem};
6dbcb073 2655
0d29ab3b 2656 foreach my $k (keys %$conf) {
a9ce7583 2657 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
d44712fc
EK
2658 # sockets are safe: they will recreated be on the target side post-migrate
2659 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
ca6abacf 2660 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
64e13401
DM
2661 }
2662
ca6abacf 2663 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
64e13401 2664
ca6abacf 2665 return \@loc_res;
64e13401
DM
2666}
2667
719893a9 2668# check if used storages are available on all nodes (use by migrate)
47152e2e
DM
2669sub check_storage_availability {
2670 my ($storecfg, $conf, $node) = @_;
2671
912792e2 2672 PVE::QemuConfig->foreach_volume($conf, sub {
47152e2e
DM
2673 my ($ds, $drive) = @_;
2674
2675 my $volid = $drive->{file};
2676 return if !$volid;
2677
2678 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2679 return if !$sid;
2680
2681 # check if storage is available on both nodes
0d2db084
FE
2682 my $scfg = PVE::Storage::storage_check_enabled($storecfg, $sid);
2683 PVE::Storage::storage_check_enabled($storecfg, $sid, $node);
24b84b47 2684
3148f0b0
TL
2685 my ($vtype) = PVE::Storage::parse_volname($storecfg, $volid);
2686
2687 die "$volid: content type '$vtype' is not available on storage '$sid'\n"
2688 if !$scfg->{content}->{$vtype};
47152e2e
DM
2689 });
2690}
2691
719893a9
DM
2692# list nodes where all VM images are available (used by has_feature API)
2693sub shared_nodes {
2694 my ($conf, $storecfg) = @_;
2695
2696 my $nodelist = PVE::Cluster::get_nodelist();
2697 my $nodehash = { map { $_ => 1 } @$nodelist };
38277afc 2698 my $nodename = nodename();
be190583 2699
912792e2 2700 PVE::QemuConfig->foreach_volume($conf, sub {
719893a9
DM
2701 my ($ds, $drive) = @_;
2702
2703 my $volid = $drive->{file};
2704 return if !$volid;
2705
2706 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2707 if ($storeid) {
2708 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2709 if ($scfg->{disable}) {
2710 $nodehash = {};
2711 } elsif (my $avail = $scfg->{nodes}) {
2712 foreach my $node (keys %$nodehash) {
2713 delete $nodehash->{$node} if !$avail->{$node};
2714 }
2715 } elsif (!$scfg->{shared}) {
2716 foreach my $node (keys %$nodehash) {
2717 delete $nodehash->{$node} if $node ne $nodename
2718 }
2719 }
2720 }
2721 });
2722
2723 return $nodehash
2724}
2725
f25852c2
TM
2726sub check_local_storage_availability {
2727 my ($conf, $storecfg) = @_;
2728
2729 my $nodelist = PVE::Cluster::get_nodelist();
2730 my $nodehash = { map { $_ => {} } @$nodelist };
2731
912792e2 2732 PVE::QemuConfig->foreach_volume($conf, sub {
f25852c2
TM
2733 my ($ds, $drive) = @_;
2734
2735 my $volid = $drive->{file};
2736 return if !$volid;
2737
2738 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2739 if ($storeid) {
2740 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2741
2742 if ($scfg->{disable}) {
2743 foreach my $node (keys %$nodehash) {
32075a2c 2744 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2745 }
2746 } elsif (my $avail = $scfg->{nodes}) {
2747 foreach my $node (keys %$nodehash) {
2748 if (!$avail->{$node}) {
32075a2c 2749 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2750 }
2751 }
2752 }
2753 }
2754 });
2755
32075a2c
TL
2756 foreach my $node (values %$nodehash) {
2757 if (my $unavail = $node->{unavailable_storages}) {
2758 $node->{unavailable_storages} = [ sort keys %$unavail ];
2759 }
2760 }
2761
f25852c2
TM
2762 return $nodehash
2763}
2764
babf613a 2765# Compat only, use assert_config_exists_on_node and vm_running_locally where possible
1e3baf05 2766sub check_running {
7e8dcf2c 2767 my ($vmid, $nocheck, $node) = @_;
1e3baf05 2768
babf613a
SR
2769 PVE::QemuConfig::assert_config_exists_on_node($vmid, $node) if !$nocheck;
2770 return PVE::QemuServer::Helpers::vm_running_locally($vmid);
1e3baf05
DM
2771}
2772
2773sub vzlist {
19672434 2774
1e3baf05
DM
2775 my $vzlist = config_list();
2776
d036e418 2777 my $fd = IO::Dir->new($PVE::QemuServer::Helpers::var_run_tmpdir) || return $vzlist;
1e3baf05 2778
19672434 2779 while (defined(my $de = $fd->read)) {
1e3baf05
DM
2780 next if $de !~ m/^(\d+)\.pid$/;
2781 my $vmid = $1;
6b64503e
DM
2782 next if !defined($vzlist->{$vmid});
2783 if (my $pid = check_running($vmid)) {
1e3baf05
DM
2784 $vzlist->{$vmid}->{pid} = $pid;
2785 }
2786 }
2787
2788 return $vzlist;
2789}
2790
b1a70cab
DM
2791our $vmstatus_return_properties = {
2792 vmid => get_standard_option('pve-vmid'),
2793 status => {
2794 description => "Qemu process status.",
2795 type => 'string',
2796 enum => ['stopped', 'running'],
2797 },
2798 maxmem => {
2799 description => "Maximum memory in bytes.",
2800 type => 'integer',
2801 optional => 1,
2802 renderer => 'bytes',
2803 },
2804 maxdisk => {
2805 description => "Root disk size in bytes.",
2806 type => 'integer',
2807 optional => 1,
2808 renderer => 'bytes',
2809 },
2810 name => {
2811 description => "VM name.",
2812 type => 'string',
2813 optional => 1,
2814 },
2815 qmpstatus => {
2816 description => "Qemu QMP agent status.",
2817 type => 'string',
2818 optional => 1,
2819 },
2820 pid => {
2821 description => "PID of running qemu process.",
2822 type => 'integer',
2823 optional => 1,
2824 },
2825 uptime => {
2826 description => "Uptime.",
2827 type => 'integer',
2828 optional => 1,
2829 renderer => 'duration',
2830 },
2831 cpus => {
2832 description => "Maximum usable CPUs.",
2833 type => 'number',
2834 optional => 1,
2835 },
e6ed61b4 2836 lock => {
11efdfa5 2837 description => "The current config lock, if any.",
e6ed61b4
DC
2838 type => 'string',
2839 optional => 1,
b8e7068a
DC
2840 },
2841 tags => {
2842 description => "The current configured tags, if any",
2843 type => 'string',
2844 optional => 1,
2845 },
949112c3
FE
2846 'running-machine' => {
2847 description => "The currently running machine type (if running).",
2848 type => 'string',
2849 optional => 1,
2850 },
2851 'running-qemu' => {
2852 description => "The currently running QEMU version (if running).",
2853 type => 'string',
2854 optional => 1,
2855 },
b1a70cab
DM
2856};
2857
1e3baf05
DM
2858my $last_proc_pid_stat;
2859
03a33f30
DM
2860# get VM status information
2861# This must be fast and should not block ($full == false)
2862# We only query KVM using QMP if $full == true (this can be slow)
1e3baf05 2863sub vmstatus {
03a33f30 2864 my ($opt_vmid, $full) = @_;
1e3baf05
DM
2865
2866 my $res = {};
2867
19672434 2868 my $storecfg = PVE::Storage::config();
1e3baf05
DM
2869
2870 my $list = vzlist();
3618ee99
EK
2871 my $defaults = load_defaults();
2872
694fcad4 2873 my ($uptime) = PVE::ProcFSTools::read_proc_uptime(1);
1e3baf05 2874
ae4915a2
DM
2875 my $cpucount = $cpuinfo->{cpus} || 1;
2876
1e3baf05
DM
2877 foreach my $vmid (keys %$list) {
2878 next if $opt_vmid && ($vmid ne $opt_vmid);
2879
9f78b695 2880 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 2881
ad2cad72 2882 my $d = { vmid => int($vmid) };
8a0addab 2883 $d->{pid} = int($list->{$vmid}->{pid}) if $list->{$vmid}->{pid};
1e3baf05
DM
2884
2885 # fixme: better status?
2886 $d->{status} = $list->{$vmid}->{pid} ? 'running' : 'stopped';
2887
776c5f50 2888 my $size = PVE::QemuServer::Drive::bootdisk_size($storecfg, $conf);
af990afe
DM
2889 if (defined($size)) {
2890 $d->{disk} = 0; # no info available
1e3baf05
DM
2891 $d->{maxdisk} = $size;
2892 } else {
2893 $d->{disk} = 0;
2894 $d->{maxdisk} = 0;
2895 }
2896
3618ee99
EK
2897 $d->{cpus} = ($conf->{sockets} || $defaults->{sockets})
2898 * ($conf->{cores} || $defaults->{cores});
ae4915a2 2899 $d->{cpus} = $cpucount if $d->{cpus} > $cpucount;
d7c8364b 2900 $d->{cpus} = $conf->{vcpus} if $conf->{vcpus};
ae4915a2 2901
1e3baf05 2902 $d->{name} = $conf->{name} || "VM $vmid";
3618ee99
EK
2903 $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024)
2904 : $defaults->{memory}*(1024*1024);
1e3baf05 2905
8b1accf7 2906 if ($conf->{balloon}) {
4bdb0514 2907 $d->{balloon_min} = $conf->{balloon}*(1024*1024);
3618ee99
EK
2908 $d->{shares} = defined($conf->{shares}) ? $conf->{shares}
2909 : $defaults->{shares};
8b1accf7
DM
2910 }
2911
1e3baf05
DM
2912 $d->{uptime} = 0;
2913 $d->{cpu} = 0;
1e3baf05
DM
2914 $d->{mem} = 0;
2915
2916 $d->{netout} = 0;
2917 $d->{netin} = 0;
2918
2919 $d->{diskread} = 0;
2920 $d->{diskwrite} = 0;
2921
75a2a423 2922 $d->{template} = 1 if PVE::QemuConfig->is_template($conf);
4d8c851b 2923
8107b378 2924 $d->{serial} = 1 if conf_has_serial($conf);
e6ed61b4 2925 $d->{lock} = $conf->{lock} if $conf->{lock};
b8e7068a 2926 $d->{tags} = $conf->{tags} if defined($conf->{tags});
8107b378 2927
1e3baf05
DM
2928 $res->{$vmid} = $d;
2929 }
2930
2931 my $netdev = PVE::ProcFSTools::read_proc_net_dev();
2932 foreach my $dev (keys %$netdev) {
2933 next if $dev !~ m/^tap([1-9]\d*)i/;
2934 my $vmid = $1;
2935 my $d = $res->{$vmid};
2936 next if !$d;
19672434 2937
1e3baf05
DM
2938 $d->{netout} += $netdev->{$dev}->{receive};
2939 $d->{netin} += $netdev->{$dev}->{transmit};
604ea644
AD
2940
2941 if ($full) {
ad2cad72
FE
2942 $d->{nics}->{$dev}->{netout} = int($netdev->{$dev}->{receive});
2943 $d->{nics}->{$dev}->{netin} = int($netdev->{$dev}->{transmit});
604ea644
AD
2944 }
2945
1e3baf05
DM
2946 }
2947
1e3baf05
DM
2948 my $ctime = gettimeofday;
2949
2950 foreach my $vmid (keys %$list) {
2951
2952 my $d = $res->{$vmid};
2953 my $pid = $d->{pid};
2954 next if !$pid;
2955
694fcad4
DM
2956 my $pstat = PVE::ProcFSTools::read_proc_pid_stat($pid);
2957 next if !$pstat; # not running
19672434 2958
694fcad4 2959 my $used = $pstat->{utime} + $pstat->{stime};
1e3baf05 2960
694fcad4 2961 $d->{uptime} = int(($uptime - $pstat->{starttime})/$cpuinfo->{user_hz});
1e3baf05 2962
694fcad4 2963 if ($pstat->{vsize}) {
6b64503e 2964 $d->{mem} = int(($pstat->{rss}/$pstat->{vsize})*$d->{maxmem});
1e3baf05
DM
2965 }
2966
2967 my $old = $last_proc_pid_stat->{$pid};
2968 if (!$old) {
19672434
DM
2969 $last_proc_pid_stat->{$pid} = {
2970 time => $ctime,
1e3baf05
DM
2971 used => $used,
2972 cpu => 0,
1e3baf05
DM
2973 };
2974 next;
2975 }
2976
7f0b5beb 2977 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz};
1e3baf05
DM
2978
2979 if ($dtime > 1000) {
2980 my $dutime = $used - $old->{used};
2981
ae4915a2 2982 $d->{cpu} = (($dutime/$dtime)* $cpucount) / $d->{cpus};
1e3baf05 2983 $last_proc_pid_stat->{$pid} = {
19672434 2984 time => $ctime,
1e3baf05
DM
2985 used => $used,
2986 cpu => $d->{cpu},
1e3baf05
DM
2987 };
2988 } else {
2989 $d->{cpu} = $old->{cpu};
1e3baf05
DM
2990 }
2991 }
2992
f5eb281a 2993 return $res if !$full;
03a33f30
DM
2994
2995 my $qmpclient = PVE::QMPClient->new();
2996
64e7fcf2
DM
2997 my $ballooncb = sub {
2998 my ($vmid, $resp) = @_;
2999
3000 my $info = $resp->{'return'};
38babf81
DM
3001 return if !$info->{max_mem};
3002
64e7fcf2
DM
3003 my $d = $res->{$vmid};
3004
38babf81
DM
3005 # use memory assigned to VM
3006 $d->{maxmem} = $info->{max_mem};
3007 $d->{balloon} = $info->{actual};
3008
3009 if (defined($info->{total_mem}) && defined($info->{free_mem})) {
3010 $d->{mem} = $info->{total_mem} - $info->{free_mem};
3011 $d->{freemem} = $info->{free_mem};
64e7fcf2
DM
3012 }
3013
604ea644 3014 $d->{ballooninfo} = $info;
64e7fcf2
DM
3015 };
3016
03a33f30
DM
3017 my $blockstatscb = sub {
3018 my ($vmid, $resp) = @_;
3019 my $data = $resp->{'return'} || [];
3020 my $totalrdbytes = 0;
3021 my $totalwrbytes = 0;
604ea644 3022
03a33f30
DM
3023 for my $blockstat (@$data) {
3024 $totalrdbytes = $totalrdbytes + $blockstat->{stats}->{rd_bytes};
3025 $totalwrbytes = $totalwrbytes + $blockstat->{stats}->{wr_bytes};
604ea644
AD
3026
3027 $blockstat->{device} =~ s/drive-//;
3028 $res->{$vmid}->{blockstat}->{$blockstat->{device}} = $blockstat->{stats};
03a33f30
DM
3029 }
3030 $res->{$vmid}->{diskread} = $totalrdbytes;
3031 $res->{$vmid}->{diskwrite} = $totalwrbytes;
3032 };
3033
949112c3
FE
3034 my $machinecb = sub {
3035 my ($vmid, $resp) = @_;
3036 my $data = $resp->{'return'} || [];
3037
3038 $res->{$vmid}->{'running-machine'} =
3039 PVE::QemuServer::Machine::current_from_query_machines($data);
3040 };
3041
3042 my $versioncb = sub {
3043 my ($vmid, $resp) = @_;
3044 my $data = $resp->{'return'} // {};
3045 my $version = 'unknown';
3046
3047 if (my $v = $data->{qemu}) {
3048 $version = $v->{major} . "." . $v->{minor} . "." . $v->{micro};
3049 }
3050
3051 $res->{$vmid}->{'running-qemu'} = $version;
3052 };
3053
03a33f30
DM
3054 my $statuscb = sub {
3055 my ($vmid, $resp) = @_;
64e7fcf2 3056
03a33f30 3057 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
949112c3
FE
3058 $qmpclient->queue_cmd($vmid, $machinecb, 'query-machines');
3059 $qmpclient->queue_cmd($vmid, $versioncb, 'query-version');
64e7fcf2
DM
3060 # this fails if ballon driver is not loaded, so this must be
3061 # the last commnand (following command are aborted if this fails).
38babf81 3062 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
03a33f30
DM
3063
3064 my $status = 'unknown';
3065 if (!defined($status = $resp->{'return'}->{status})) {
3066 warn "unable to get VM status\n";
3067 return;
3068 }
3069
3070 $res->{$vmid}->{qmpstatus} = $resp->{'return'}->{status};
3071 };
3072
3073 foreach my $vmid (keys %$list) {
3074 next if $opt_vmid && ($vmid ne $opt_vmid);
3075 next if !$res->{$vmid}->{pid}; # not running
3076 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3077 }
3078
b017fbda 3079 $qmpclient->queue_execute(undef, 2);
03a33f30 3080
6891fd70
SR
3081 foreach my $vmid (keys %$list) {
3082 next if $opt_vmid && ($vmid ne $opt_vmid);
e5b18771
FG
3083 next if !$res->{$vmid}->{pid}; #not running
3084
6891fd70
SR
3085 # we can't use the $qmpclient since it might have already aborted on
3086 # 'query-balloon', but this might also fail for older versions...
3087 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
3088 $res->{$vmid}->{'proxmox-support'} = $qemu_support // {};
3089 }
3090
03a33f30
DM
3091 foreach my $vmid (keys %$list) {
3092 next if $opt_vmid && ($vmid ne $opt_vmid);
3093 $res->{$vmid}->{qmpstatus} = $res->{$vmid}->{status} if !$res->{$vmid}->{qmpstatus};
3094 }
3095
1e3baf05
DM
3096 return $res;
3097}
3098
8107b378
DC
3099sub conf_has_serial {
3100 my ($conf) = @_;
3101
3102 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3103 if ($conf->{"serial$i"}) {
3104 return 1;
3105 }
3106 }
3107
3108 return 0;
3109}
3110
d5535a00
TL
3111sub conf_has_audio {
3112 my ($conf, $id) = @_;
3113
3114 $id //= 0;
3115 my $audio = $conf->{"audio$id"};
d1c1af4b 3116 return if !defined($audio);
d5535a00 3117
4df98f2f 3118 my $audioproperties = parse_property_string($audio_fmt, $audio);
d5535a00
TL
3119 my $audiodriver = $audioproperties->{driver} // 'spice';
3120
3121 return {
3122 dev => $audioproperties->{device},
b0f96836 3123 dev_id => "audiodev$id",
d5535a00
TL
3124 backend => $audiodriver,
3125 backend_id => "$audiodriver-backend${id}",
3126 };
3127}
3128
b01de199 3129sub audio_devs {
1cc5ed1b 3130 my ($audio, $audiopciaddr, $machine_version) = @_;
b01de199
TL
3131
3132 my $devs = [];
3133
3134 my $id = $audio->{dev_id};
1cc5ed1b
AL
3135 my $audiodev = "";
3136 if (min_version($machine_version, 4, 2)) {
3137 $audiodev = ",audiodev=$audio->{backend_id}";
3138 }
b01de199
TL
3139
3140 if ($audio->{dev} eq 'AC97') {
1cc5ed1b 3141 push @$devs, '-device', "AC97,id=${id}${audiopciaddr}$audiodev";
b01de199
TL
3142 } elsif ($audio->{dev} =~ /intel\-hda$/) {
3143 push @$devs, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
1cc5ed1b
AL
3144 push @$devs, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0$audiodev";
3145 push @$devs, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1$audiodev";
b01de199
TL
3146 } else {
3147 die "unkown audio device '$audio->{dev}', implement me!";
3148 }
3149
3150 push @$devs, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
3151
3152 return $devs;
3153}
3154
f9dde219
SR
3155sub get_tpm_paths {
3156 my ($vmid) = @_;
3157 return {
3158 socket => "/var/run/qemu-server/$vmid.swtpm",
3159 pid => "/var/run/qemu-server/$vmid.swtpm.pid",
3160 };
3161}
3162
3163sub add_tpm_device {
3164 my ($vmid, $devices, $conf) = @_;
3165
3166 return if !$conf->{tpmstate0};
3167
3168 my $paths = get_tpm_paths($vmid);
3169
3170 push @$devices, "-chardev", "socket,id=tpmchar,path=$paths->{socket}";
3171 push @$devices, "-tpmdev", "emulator,id=tpmdev,chardev=tpmchar";
3172 push @$devices, "-device", "tpm-tis,tpmdev=tpmdev";
3173}
3174
3175sub start_swtpm {
3176 my ($storecfg, $vmid, $tpmdrive, $migration) = @_;
3177
3178 return if !$tpmdrive;
3179
3180 my $state;
3181 my $tpm = parse_drive("tpmstate0", $tpmdrive);
3182 my ($storeid, $volname) = PVE::Storage::parse_volume_id($tpm->{file}, 1);
3183 if ($storeid) {
3184 $state = PVE::Storage::map_volume($storecfg, $tpm->{file});
3185 } else {
3186 $state = $tpm->{file};
3187 }
3188
3189 my $paths = get_tpm_paths($vmid);
3190
3191 # during migration, we will get state from remote
3192 #
3193 if (!$migration) {
3194 # run swtpm_setup to create a new TPM state if it doesn't exist yet
3195 my $setup_cmd = [
3196 "swtpm_setup",
3197 "--tpmstate",
3198 "file://$state",
3199 "--createek",
3200 "--create-ek-cert",
3201 "--create-platform-cert",
3202 "--lock-nvram",
3203 "--config",
3204 "/etc/swtpm_setup.conf", # do not use XDG configs
3205 "--runas",
3206 "0", # force creation as root, error if not possible
3207 "--not-overwrite", # ignore existing state, do not modify
3208 ];
3209
3210 push @$setup_cmd, "--tpm2" if $tpm->{version} eq 'v2.0';
3211 # TPM 2.0 supports ECC crypto, use if possible
3212 push @$setup_cmd, "--ecc" if $tpm->{version} eq 'v2.0';
3213
3214 run_command($setup_cmd, outfunc => sub {
3215 print "swtpm_setup: $1\n";
3216 });
3217 }
3218
3219 my $emulator_cmd = [
3220 "swtpm",
3221 "socket",
3222 "--tpmstate",
3223 "backend-uri=file://$state,mode=0600",
3224 "--ctrl",
3225 "type=unixio,path=$paths->{socket},mode=0600",
3226 "--pid",
3227 "file=$paths->{pid}",
3228 "--terminate", # terminate on QEMU disconnect
3229 "--daemon",
3230 ];
3231 push @$emulator_cmd, "--tpm2" if $tpm->{version} eq 'v2.0';
3232 run_command($emulator_cmd, outfunc => sub { print $1; });
3233
6bbcd71f 3234 my $tries = 100; # swtpm may take a bit to start before daemonizing, wait up to 5s for pid
f85951dc 3235 while (! -e $paths->{pid}) {
90c41bac 3236 die "failed to start swtpm: pid file '$paths->{pid}' wasn't created.\n" if --$tries == 0;
6bbcd71f 3237 usleep(50_000);
f85951dc
SR
3238 }
3239
f9dde219
SR
3240 # return untainted PID of swtpm daemon so it can be killed on error
3241 file_read_firstline($paths->{pid}) =~ m/(\d+)/;
3242 return $1;
3243}
3244
86b8228b
DM
3245sub vga_conf_has_spice {
3246 my ($vga) = @_;
3247
55655ebc
DC
3248 my $vgaconf = parse_vga($vga);
3249 my $vgatype = $vgaconf->{type};
3250 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
590e698c
DM
3251
3252 return $1 || 1;
86b8228b
DM
3253}
3254
d731ecbe
WB
3255sub is_native($) {
3256 my ($arch) = @_;
3257 return get_host_arch() eq $arch;
3258}
3259
045749f2
TL
3260sub get_vm_arch {
3261 my ($conf) = @_;
3262 return $conf->{arch} // get_host_arch();
3263}
3264
d731ecbe
WB
3265my $default_machines = {
3266 x86_64 => 'pc',
3267 aarch64 => 'virt',
3268};
3269
0761e619
TL
3270sub get_installed_machine_version {
3271 my ($kvmversion) = @_;
3272 $kvmversion = kvm_user_version() if !defined($kvmversion);
3273 $kvmversion =~ m/^(\d+\.\d+)/;
3274 return $1;
3275}
3276
3277sub windows_get_pinned_machine_version {
3278 my ($machine, $base_version, $kvmversion) = @_;
3279
3280 my $pin_version = $base_version;
3281 if (!defined($base_version) ||
3282 !PVE::QemuServer::Machine::can_run_pve_machine_version($base_version, $kvmversion)
3283 ) {
3284 $pin_version = get_installed_machine_version($kvmversion);
3285 }
3286 if (!$machine || $machine eq 'pc') {
3287 $machine = "pc-i440fx-$pin_version";
3288 } elsif ($machine eq 'q35') {
3289 $machine = "pc-q35-$pin_version";
3290 } elsif ($machine eq 'virt') {
3291 $machine = "virt-$pin_version";
3292 } else {
3293 warn "unknown machine type '$machine', not touching that!\n";
3294 }
3295
3296 return $machine;
3297}
3298
045749f2 3299sub get_vm_machine {
ac0077cc 3300 my ($conf, $forcemachine, $arch, $add_pve_version, $kvmversion) = @_;
045749f2
TL
3301
3302 my $machine = $forcemachine || $conf->{machine};
d731ecbe 3303
9471e48b 3304 if (!$machine || $machine =~ m/^(?:pc|q35|virt)$/) {
4dd1e83c
TL
3305 $kvmversion //= kvm_user_version();
3306 # we must pin Windows VMs without a specific version to 5.1, as 5.2 fixed a bug in ACPI
3307 # layout which confuses windows quite a bit and may result in various regressions..
3308 # see: https://lists.gnu.org/archive/html/qemu-devel/2021-02/msg08484.html
3309 if (windows_version($conf->{ostype})) {
0761e619 3310 $machine = windows_get_pinned_machine_version($machine, '5.1', $kvmversion);
4dd1e83c 3311 }
045749f2
TL
3312 $arch //= 'x86_64';
3313 $machine ||= $default_machines->{$arch};
ac0077cc 3314 if ($add_pve_version) {
ac0077cc
SR
3315 my $pvever = PVE::QemuServer::Machine::get_pve_version($kvmversion);
3316 $machine .= "+pve$pvever";
3317 }
3318 }
3319
d4be7f31
SR
3320 if ($add_pve_version && $machine !~ m/\+pve\d+?(?:\.pxe)?$/) {
3321 my $is_pxe = $machine =~ m/^(.*?)\.pxe$/;
3322 $machine = $1 if $is_pxe;
3323
ac0077cc
SR
3324 # for version-pinned machines that do not include a pve-version (e.g.
3325 # pc-q35-4.1), we assume 0 to keep them stable in case we bump
3326 $machine .= '+pve0';
d4be7f31
SR
3327
3328 $machine .= '.pxe' if $is_pxe;
045749f2
TL
3329 }
3330
3331 return $machine;
d731ecbe
WB
3332}
3333
90b20b15
DC
3334sub get_ovmf_files($$$) {
3335 my ($arch, $efidisk, $smm) = @_;
96ed3574 3336
b5099b4f 3337 my $types = $OVMF->{$arch}
96ed3574
WB
3338 or die "no OVMF images known for architecture '$arch'\n";
3339
b5099b4f
SR
3340 my $type = 'default';
3341 if (defined($efidisk->{efitype}) && $efidisk->{efitype} eq '4m') {
90b20b15
DC
3342 $type = $smm ? "4m" : "4m-no-smm";
3343 $type .= '-ms' if $efidisk->{'pre-enrolled-keys'};
b5099b4f
SR
3344 }
3345
3346 return $types->{$type}->@*;
96ed3574
WB
3347}
3348
6908fd9b
WB
3349my $Arch2Qemu = {
3350 aarch64 => '/usr/bin/qemu-system-aarch64',
3351 x86_64 => '/usr/bin/qemu-system-x86_64',
3352};
3353sub get_command_for_arch($) {
3354 my ($arch) = @_;
3355 return '/usr/bin/kvm' if is_native($arch);
3356
3357 my $cmd = $Arch2Qemu->{$arch}
3358 or die "don't know how to emulate architecture '$arch'\n";
3359 return $cmd;
3360}
3361
05a4c550
SR
3362# To use query_supported_cpu_flags and query_understood_cpu_flags to get flags
3363# to use in a QEMU command line (-cpu element), first array_intersect the result
3364# of query_supported_ with query_understood_. This is necessary because:
3365#
3366# a) query_understood_ returns flags the host cannot use and
3367# b) query_supported_ (rather the QMP call) doesn't actually return CPU
3368# flags, but CPU settings - with most of them being flags. Those settings
3369# (and some flags, curiously) cannot be specified as a "-cpu" argument.
3370#
3371# query_supported_ needs to start up to 2 temporary VMs and is therefore rather
3372# expensive. If you need the value returned from this, you can get it much
3373# cheaper from pmxcfs using PVE::Cluster::get_node_kv('cpuflags-$accel') with
3374# $accel being 'kvm' or 'tcg'.
3375#
3376# pvestatd calls this function on startup and whenever the QEMU/KVM version
3377# changes, automatically populating pmxcfs.
3378#
3379# Returns: { kvm => [ flagX, flagY, ... ], tcg => [ flag1, flag2, ... ] }
3380# since kvm and tcg machines support different flags
3381#
3382sub query_supported_cpu_flags {
52cffab6 3383 my ($arch) = @_;
05a4c550 3384
52cffab6
SR
3385 $arch //= get_host_arch();
3386 my $default_machine = $default_machines->{$arch};
3387
3388 my $flags = {};
05a4c550
SR
3389
3390 # FIXME: Once this is merged, the code below should work for ARM as well:
3391 # https://lists.nongnu.org/archive/html/qemu-devel/2019-06/msg04947.html
3392 die "QEMU/KVM cannot detect CPU flags on ARM (aarch64)\n" if
3393 $arch eq "aarch64";
3394
3395 my $kvm_supported = defined(kvm_version());
3396 my $qemu_cmd = get_command_for_arch($arch);
3397 my $fakevmid = -1;
3398 my $pidfile = PVE::QemuServer::Helpers::pidfile_name($fakevmid);
3399
3400 # Start a temporary (frozen) VM with vmid -1 to allow sending a QMP command
3401 my $query_supported_run_qemu = sub {
3402 my ($kvm) = @_;
3403
3404 my $flags = {};
3405 my $cmd = [
3406 $qemu_cmd,
3407 '-machine', $default_machine,
3408 '-display', 'none',
378ad769 3409 '-chardev', "socket,id=qmp,path=/var/run/qemu-server/$fakevmid.qmp,server=on,wait=off",
05a4c550
SR
3410 '-mon', 'chardev=qmp,mode=control',
3411 '-pidfile', $pidfile,
3412 '-S', '-daemonize'
3413 ];
3414
3415 if (!$kvm) {
3416 push @$cmd, '-accel', 'tcg';
3417 }
3418
3419 my $rc = run_command($cmd, noerr => 1, quiet => 0);
3420 die "QEMU flag querying VM exited with code " . $rc if $rc;
3421
3422 eval {
3423 my $cmd_result = mon_cmd(
3424 $fakevmid,
3425 'query-cpu-model-expansion',
3426 type => 'full',
3427 model => { name => 'host' }
3428 );
3429
3430 my $props = $cmd_result->{model}->{props};
3431 foreach my $prop (keys %$props) {
3432 next if $props->{$prop} ne '1';
3433 # QEMU returns some flags multiple times, with '_', '.' or '-'
3434 # (e.g. lahf_lm and lahf-lm; sse4.2, sse4-2 and sse4_2; ...).
3435 # We only keep those with underscores, to match /proc/cpuinfo
3436 $prop =~ s/\.|-/_/g;
3437 $flags->{$prop} = 1;
3438 }
3439 };
3440 my $err = $@;
3441
6bbcd71f 3442 # force stop with 10 sec timeout and 'nocheck', always stop, even if QMP failed
05a4c550
SR
3443 vm_stop(undef, $fakevmid, 1, 1, 10, 0, 1);
3444
3445 die $err if $err;
3446
3447 return [ sort keys %$flags ];
3448 };
3449
3450 # We need to query QEMU twice, since KVM and TCG have different supported flags
3451 PVE::QemuConfig->lock_config($fakevmid, sub {
3452 $flags->{tcg} = eval { $query_supported_run_qemu->(0) };
3453 warn "warning: failed querying supported tcg flags: $@\n" if $@;
3454
3455 if ($kvm_supported) {
3456 $flags->{kvm} = eval { $query_supported_run_qemu->(1) };
3457 warn "warning: failed querying supported kvm flags: $@\n" if $@;
3458 }
3459 });
3460
3461 return $flags;
3462}
3463
3464# Understood CPU flags are written to a file at 'pve-qemu' compile time
3465my $understood_cpu_flag_dir = "/usr/share/kvm";
3466sub query_understood_cpu_flags {
3467 my $arch = get_host_arch();
3468 my $filepath = "$understood_cpu_flag_dir/recognized-CPUID-flags-$arch";
3469
3470 die "Cannot query understood QEMU CPU flags for architecture: $arch (file not found)\n"
3471 if ! -e $filepath;
3472
3473 my $raw = file_get_contents($filepath);
3474 $raw =~ s/^\s+|\s+$//g;
3475 my @flags = split(/\s+/, $raw);
3476
3477 return \@flags;
3478}
3479
e5a6919c
FE
3480# Since commit 277d33454f77ec1d1e0bc04e37621e4dd2424b67 in pve-qemu, smm is not off by default
3481# anymore. But smm=off seems to be required when using SeaBIOS and serial display.
3482my sub should_disable_smm {
3483 my ($conf, $vga) = @_;
3484
3485 return (!defined($conf->{bios}) || $conf->{bios} eq 'seabios') &&
bec87424 3486 $vga->{type} && $vga->{type} =~ m/^(serial\d+|none)$/;
e5a6919c
FE
3487}
3488
1e3baf05 3489sub config_to_command {
5921764c
SR
3490 my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
3491 $pbs_backing) = @_;
1e3baf05
DM
3492
3493 my $cmd = [];
3326ae19 3494 my ($globalFlags, $machineFlags, $rtcFlags) = ([], [], []);
5bdcf937 3495 my $devices = [];
5bdcf937 3496 my $bridges = {};
b42d3cf9 3497 my $ostype = $conf->{ostype};
4317f69f 3498 my $winversion = windows_version($ostype);
d731ecbe 3499 my $kvm = $conf->{kvm};
38277afc 3500 my $nodename = nodename();
d731ecbe 3501
045749f2 3502 my $arch = get_vm_arch($conf);
1476b99f
DC
3503 my $kvm_binary = get_command_for_arch($arch);
3504 my $kvmver = kvm_user_version($kvm_binary);
045749f2 3505
a04dd5c4
SR
3506 if (!$kvmver || $kvmver !~ m/^(\d+)\.(\d+)/ || $1 < 3) {
3507 $kvmver //= "undefined";
3508 die "Detected old QEMU binary ('$kvmver', at least 3.0 is required)\n";
3509 }
3510
9471e48b
TL
3511 my $add_pve_version = min_version($kvmver, 4, 1);
3512
3513 my $machine_type = get_vm_machine($conf, $forcemachine, $arch, $add_pve_version);
4df98f2f 3514 my $machine_version = extract_version($machine_type, $kvmver);
d731ecbe 3515 $kvm //= 1 if is_native($arch);
4317f69f 3516
a77a53ae 3517 $machine_version =~ m/(\d+)\.(\d+)/;
ac0077cc 3518 my ($machine_major, $machine_minor) = ($1, $2);
ac0077cc 3519
b516c848
SR
3520 if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
3521 warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
3522 } elsif (!min_version($kvmver, $machine_major, $machine_minor)) {
4df98f2f
TL
3523 die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
3524 ." please upgrade node '$nodename'\n"
b516c848 3525 } elsif (!PVE::QemuServer::Machine::can_run_pve_machine_version($machine_version, $kvmver)) {
ac0077cc 3526 my $max_pve_version = PVE::QemuServer::Machine::get_pve_version($machine_version);
4df98f2f
TL
3527 die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
3528 ." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
3529 ." node '$nodename'\n";
ac0077cc
SR
3530 }
3531
3532 # if a specific +pve version is required for a feature, use $version_guard
3533 # instead of min_version to allow machines to be run with the minimum
3534 # required version
3535 my $required_pve_version = 0;
3536 my $version_guard = sub {
3537 my ($major, $minor, $pve) = @_;
3538 return 0 if !min_version($machine_version, $major, $minor, $pve);
47f35977
SR
3539 my $max_pve = PVE::QemuServer::Machine::get_pve_version("$major.$minor");
3540 return 1 if min_version($machine_version, $major, $minor, $max_pve+1);
ac0077cc
SR
3541 $required_pve_version = $pve if $pve && $pve > $required_pve_version;
3542 return 1;
3543 };
a77a53ae 3544
4df98f2f
TL
3545 if ($kvm && !defined kvm_version()) {
3546 die "KVM virtualisation configured, but not available. Either disable in VM configuration"
3547 ." or enable in BIOS.\n";
d731ecbe 3548 }
bfcd9b7e 3549
3392d6ca 3550 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
4d3f29ed 3551 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
249c4a6c
AD
3552 my $use_old_bios_files = undef;
3553 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
db656e5f 3554
83870398 3555 if ($conf->{affinity}) {
c963efc8 3556 push @$cmd, "/usr/bin/taskset";
83870398
DB
3557 push @$cmd, "--cpu-list";
3558 push @$cmd, "--all-tasks";
3559 push @$cmd, $conf->{affinity};
3560 }
3561
1476b99f 3562 push @$cmd, $kvm_binary;
1e3baf05
DM
3563
3564 push @$cmd, '-id', $vmid;
3565
e4d4cda1
HR
3566 my $vmname = $conf->{name} || "vm$vmid";
3567
6884a7d7 3568 push @$cmd, '-name', "$vmname,debug-threads=on";
e4d4cda1 3569
27b25d03
SR
3570 push @$cmd, '-no-shutdown';
3571
1e3baf05
DM
3572 my $use_virtio = 0;
3573
d036e418 3574 my $qmpsocket = PVE::QemuServer::Helpers::qmp_socket($vmid);
378ad769 3575 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server=on,wait=off";
c971c4f2
AD
3576 push @$cmd, '-mon', "chardev=qmp,mode=control";
3577
2ea5fb7e 3578 if (min_version($machine_version, 2, 12)) {
b4496b9e 3579 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
71bd73b5
DC
3580 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3581 }
1e3baf05 3582
d036e418 3583 push @$cmd, '-pidfile' , PVE::QemuServer::Helpers::pidfile_name($vmid);
19672434 3584
1e3baf05
DM
3585 push @$cmd, '-daemonize';
3586
2796e7d5 3587 if ($conf->{smbios1}) {
1f30ac3a
CE
3588 my $smbios_conf = parse_smbios1($conf->{smbios1});
3589 if ($smbios_conf->{base64}) {
3590 # Do not pass base64 flag to qemu
3591 delete $smbios_conf->{base64};
3592 my $smbios_string = "";
3593 foreach my $key (keys %$smbios_conf) {
3594 my $value;
3595 if ($key eq "uuid") {
3596 $value = $smbios_conf->{uuid}
3597 } else {
3598 $value = decode_base64($smbios_conf->{$key});
3599 }
3600 # qemu accepts any binary data, only commas need escaping by double comma
3601 $value =~ s/,/,,/g;
3602 $smbios_string .= "," . $key . "=" . $value if $value;
3603 }
3604 push @$cmd, '-smbios', "type=1" . $smbios_string;
3605 } else {
3606 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3607 }
2796e7d5
DM
3608 }
3609
3edb45e7 3610 if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
b5099b4f
SR
3611 my $d;
3612 if (my $efidisk = $conf->{efidisk0}) {
3613 $d = parse_drive('efidisk0', $efidisk);
3614 }
3615
90b20b15 3616 my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch, $d, $q35);
818c3b8d 3617 die "uefi base image '$ovmf_code' not found\n" if ! -f $ovmf_code;
2ddc0a5c 3618
818c3b8d 3619 my ($path, $format);
b4dc6475 3620 my $read_only_str = '';
b5099b4f 3621 if ($d) {
2ddc0a5c 3622 my ($storeid, $volname) = PVE::Storage::parse_volume_id($d->{file}, 1);
13bca7b4 3623 $format = $d->{format};
2ddc0a5c
DC
3624 if ($storeid) {
3625 $path = PVE::Storage::path($storecfg, $d->{file});
13bca7b4
WB
3626 if (!defined($format)) {
3627 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
3628 $format = qemu_img_format($scfg, $volname);
3629 }
2ddc0a5c
DC
3630 } else {
3631 $path = $d->{file};
13bca7b4
WB
3632 die "efidisk format must be specified\n"
3633 if !defined($format);
2ddc0a5c 3634 }
b4dc6475
FG
3635
3636 $read_only_str = ',readonly=on' if drive_is_read_only($conf, $d);
2ddc0a5c 3637 } else {
34e82fa2 3638 log_warn("no efidisk configured! Using temporary efivars disk.");
4dcce9ee 3639 $path = "/tmp/$vmid-ovmf.fd";
96ed3574 3640 PVE::Tools::file_copy($ovmf_vars, $path, -s $ovmf_vars);
13bca7b4 3641 $format = 'raw';
2ddc0a5c 3642 }
4dcce9ee 3643
818ce80e
DC
3644 my $size_str = "";
3645
3646 if ($format eq 'raw' && $version_guard->(4, 1, 2)) {
3647 $size_str = ",size=" . (-s $ovmf_vars);
3648 }
3649
738dc81c
TL
3650 # SPI flash does lots of read-modify-write OPs, without writeback this gets really slow #3329
3651 my $cache = "";
3652 if ($path =~ m/^rbd:/) {
3653 $cache = ',cache=writeback';
3654 $path .= ':rbd_cache_policy=writeback'; # avoid write-around, we *need* to cache writes too
3655 }
6aaad230 3656
378ad769 3657 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code";
b4dc6475 3658 push @$cmd, '-drive', "if=pflash,unit=1$cache,format=$format,id=drive-efidisk0$size_str,file=${path}${read_only_str}";
a783c78e
AD
3659 }
3660
483ceeab 3661 if ($q35) { # tell QEMU to load q35 config early
7583d156 3662 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
2ea5fb7e 3663 if (min_version($machine_version, 4, 0)) {
7583d156
DC
3664 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3665 } else {
3666 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3667 }
3668 }
da8b4189 3669
cc181036
TL
3670 if (defined(my $fixups = qemu_created_version_fixups($conf, $forcemachine, $kvmver))) {
3671 push @$cmd, $fixups->@*;
3672 }
3673
844d8fa6
DC
3674 if ($conf->{vmgenid}) {
3675 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid};
3676 }
3677
d40e5e18 3678 # add usb controllers
4df98f2f
TL
3679 my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers(
3680 $conf, $bridges, $arch, $machine_type, $usbdesc->{format}, $MAX_USB_DEVICES);
d40e5e18 3681 push @$devices, @usbcontrollers if @usbcontrollers;
55655ebc 3682 my $vga = parse_vga($conf->{vga});
2fa3151e 3683
55655ebc
DC
3684 my $qxlnum = vga_conf_has_spice($conf->{vga});
3685 $vga->{type} = 'qxl' if $qxlnum;
2fa3151e 3686
55655ebc 3687 if (!$vga->{type}) {
869ad4a7
WB
3688 if ($arch eq 'aarch64') {
3689 $vga->{type} = 'virtio';
2ea5fb7e 3690 } elsif (min_version($machine_version, 2, 9)) {
55655ebc 3691 $vga->{type} = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3692 } else {
55655ebc 3693 $vga->{type} = ($winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3694 }
5acbfe9e
DM
3695 }
3696
1e3baf05 3697 # enable absolute mouse coordinates (needed by vnc)
fa3b3ce0
TL
3698 my $tablet = $conf->{tablet};
3699 if (!defined($tablet)) {
5acbfe9e 3700 $tablet = $defaults->{tablet};
590e698c 3701 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
55655ebc 3702 $tablet = 0 if $vga->{type} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
5acbfe9e
DM
3703 }
3704
d559309f
WB
3705 if ($tablet) {
3706 push @$devices, '-device', print_tabletdevice_full($conf, $arch) if $tablet;
3707 my $kbd = print_keyboarddevice_full($conf, $arch);
3708 push @$devices, '-device', $kbd if defined($kbd);
3709 }
b467f79a 3710
e5d611c3 3711 my $bootorder = device_bootorder($conf);
2141a802 3712
74c17b7a 3713 # host pci device passthrough
13d68979 3714 my ($kvm_off, $gpu_passthrough, $legacy_igd) = PVE::QemuServer::PCI::print_hostpci_devices(
41af2dfc 3715 $vmid, $conf, $devices, $vga, $winversion, $q35, $bridges, $arch, $machine_type, $bootorder);
1e3baf05
DM
3716
3717 # usb devices
ae36393d 3718 my $usb_dev_features = {};
2ea5fb7e 3719 $usb_dev_features->{spice_usb3} = 1 if min_version($machine_version, 4, 0);
ae36393d 3720
4df98f2f 3721 my @usbdevices = PVE::QemuServer::USB::get_usb_devices(
2141a802 3722 $conf, $usbdesc->{format}, $MAX_USB_DEVICES, $usb_dev_features, $bootorder);
d40e5e18 3723 push @$devices, @usbdevices if @usbdevices;
2141a802 3724
1e3baf05 3725 # serial devices
bae179aa 3726 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
fa3b3ce0
TL
3727 my $path = $conf->{"serial$i"} or next;
3728 if ($path eq 'socket') {
3729 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3730 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server=on,wait=off";
3731 # On aarch64, serial0 is the UART device. Qemu only allows
3732 # connecting UART devices via the '-serial' command line, as
3733 # the device has a fixed slot on the hardware...
3734 if ($arch eq 'aarch64' && $i == 0) {
3735 push @$devices, '-serial', "chardev:serial$i";
9f9d2fb2 3736 } else {
9f9d2fb2
DM
3737 push @$devices, '-device', "isa-serial,chardev=serial$i";
3738 }
fa3b3ce0
TL
3739 } else {
3740 die "no such serial device\n" if ! -c $path;
3741 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3742 push @$devices, '-device', "isa-serial,chardev=serial$i";
34978be3 3743 }
1e3baf05
DM
3744 }
3745
3746 # parallel devices
1989a89c 3747 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
34978be3 3748 if (my $path = $conf->{"parallel$i"}) {
19672434 3749 die "no such parallel device\n" if ! -c $path;
32e69805 3750 my $devtype = $path =~ m!^/dev/usb/lp! ? 'tty' : 'parport';
4c5dbaf6 3751 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
5bdcf937 3752 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
34978be3 3753 }
1e3baf05
DM
3754 }
3755
b01de199 3756 if (min_version($machine_version, 4, 0) && (my $audio = conf_has_audio($conf))) {
2e7b5925 3757 my $audiopciaddr = print_pci_addr("audio0", $bridges, $arch, $machine_type);
1cc5ed1b 3758 my $audio_devs = audio_devs($audio, $audiopciaddr, $machine_version);
b01de199 3759 push @$devices, @$audio_devs;
2e7b5925 3760 }
19672434 3761
f9dde219
SR
3762 add_tpm_device($vmid, $devices, $conf);
3763
1e3baf05
DM
3764 my $sockets = 1;
3765 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3766 $sockets = $conf->{sockets} if $conf->{sockets};
3767
3768 my $cores = $conf->{cores} || 1;
3bd18e48 3769
de9d1e55 3770 my $maxcpus = $sockets * $cores;
76267728 3771
de9d1e55 3772 my $vcpus = $conf->{vcpus} ? $conf->{vcpus} : $maxcpus;
76267728 3773
de9d1e55
AD
3774 my $allowed_vcpus = $cpuinfo->{cpus};
3775
483ceeab 3776 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n" if ($allowed_vcpus < $maxcpus);
1e3baf05 3777
483ceeab 3778 if ($hotplug_features->{cpu} && min_version($machine_version, 2, 7)) {
69c81430
AD
3779 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3780 for (my $i = 2; $i <= $vcpus; $i++) {
3781 my $cpustr = print_cpu_device($conf,$i);
3782 push @$cmd, '-device', $cpustr;
3783 }
3784
3785 } else {
3786
3787 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3788 }
1e3baf05
DM
3789 push @$cmd, '-nodefaults';
3790
dbea4415 3791 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
1e3baf05 3792
6b64503e 3793 push @$cmd, '-no-acpi' if defined($conf->{acpi}) && $conf->{acpi} == 0;
1e3baf05 3794
6b64503e 3795 push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
1e3baf05 3796
84902837 3797 if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none'){
4df98f2f
TL
3798 push @$devices, '-device', print_vga_device(
3799 $conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
6f070e39
TL
3800
3801 push @$cmd, '-display', 'egl-headless,gl=core' if $vga->{type} eq 'virtio-gl'; # VIRGL
3802
d036e418 3803 my $socket = PVE::QemuServer::Helpers::vnc_socket($vmid);
378ad769 3804 push @$cmd, '-vnc', "unix:$socket,password=on";
b7be4ba9 3805 } else {
55655ebc 3806 push @$cmd, '-vga', 'none' if $vga->{type} eq 'none';
b7be4ba9
AD
3807 push @$cmd, '-nographic';
3808 }
3809
1e3baf05 3810 # time drift fix
6b64503e 3811 my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
8c559505 3812 my $useLocaltime = $conf->{localtime};
1e3baf05 3813
4317f69f
AD
3814 if ($winversion >= 5) { # windows
3815 $useLocaltime = 1 if !defined($conf->{localtime});
7a131888 3816
4317f69f
AD
3817 # use time drift fix when acpi is enabled
3818 if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) {
3819 $tdf = 1 if !defined($conf->{tdf});
462e8d19 3820 }
4317f69f 3821 }
462e8d19 3822
4317f69f
AD
3823 if ($winversion >= 6) {
3824 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3825 push @$cmd, '-no-hpet';
1e3baf05
DM
3826 }
3827
8c559505
DM
3828 push @$rtcFlags, 'driftfix=slew' if $tdf;
3829
2f6f002c 3830 if ($conf->{startdate} && $conf->{startdate} ne 'now') {
8c559505
DM
3831 push @$rtcFlags, "base=$conf->{startdate}";
3832 } elsif ($useLocaltime) {
3833 push @$rtcFlags, 'base=localtime';
3834 }
1e3baf05 3835
58c64ad5
SR
3836 if ($forcecpu) {
3837 push @$cmd, '-cpu', $forcecpu;
3838 } else {
2f6f002c 3839 push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough);
58c64ad5 3840 }
519ed28c 3841
0567a4d5 3842 PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
370b05e7 3843
1e3baf05
DM
3844 push @$cmd, '-S' if $conf->{freeze};
3845
b20df606 3846 push @$cmd, '-k', $conf->{keyboard} if defined($conf->{keyboard});
1e3baf05 3847
48657158
MD
3848 my $guest_agent = parse_guest_agent($conf);
3849
3850 if ($guest_agent->{enabled}) {
d036e418 3851 my $qgasocket = PVE::QemuServer::Helpers::qmp_socket($vmid, 1);
378ad769 3852 push @$devices, '-chardev', "socket,path=$qgasocket,server=on,wait=off,id=qga0";
48657158 3853
60f03a11 3854 if (!$guest_agent->{type} || $guest_agent->{type} eq 'virtio') {
48657158
MD
3855 my $pciaddr = print_pci_addr("qga0", $bridges, $arch, $machine_type);
3856 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3857 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3858 } elsif ($guest_agent->{type} eq 'isa') {
3859 push @$devices, '-device', "isa-serial,chardev=qga0";
3860 }
ab6a046f
AD
3861 }
3862
e5d611c3
TL
3863 my $rng = $conf->{rng0} ? parse_rng($conf->{rng0}) : undef;
3864 if ($rng && $version_guard->(4, 1, 2)) {
05853188
SR
3865 check_rng_source($rng->{source});
3866
2cf61f33
SR
3867 my $max_bytes = $rng->{max_bytes} // $rng_fmt->{max_bytes}->{default};
3868 my $period = $rng->{period} // $rng_fmt->{period}->{default};
2cf61f33
SR
3869 my $limiter_str = "";
3870 if ($max_bytes) {
3871 $limiter_str = ",max-bytes=$max_bytes,period=$period";
3872 }
3873
2cf61f33 3874 my $rng_addr = print_pci_addr("rng0", $bridges, $arch, $machine_type);
2cf61f33
SR
3875 push @$devices, '-object', "rng-random,filename=$rng->{source},id=rng0";
3876 push @$devices, '-device', "virtio-rng-pci,rng=rng0$limiter_str$rng_addr";
3877 }
3878
1d794448 3879 my $spice_port;
2fa3151e 3880
f8ea1b30 3881 if ($qxlnum || $vga->{type} =~ /^virtio/) {
590e698c 3882 if ($qxlnum > 1) {
ac087616 3883 if ($winversion){
2f6f002c 3884 for (my $i = 1; $i < $qxlnum; $i++){
4df98f2f
TL
3885 push @$devices, '-device', print_vga_device(
3886 $conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
590e698c
DM
3887 }
3888 } else {
3889 # assume other OS works like Linux
55655ebc
DC
3890 my ($ram, $vram) = ("134217728", "67108864");
3891 if ($vga->{memory}) {
3892 $ram = PVE::Tools::convert_size($qxlnum*4*$vga->{memory}, 'mb' => 'b');
3893 $vram = PVE::Tools::convert_size($qxlnum*2*$vga->{memory}, 'mb' => 'b');
3894 }
3895 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3896 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
2fa3151e
AD
3897 }
3898 }
3899
d559309f 3900 my $pciaddr = print_pci_addr("spice", $bridges, $arch, $machine_type);
95a4b4a9 3901
af0eba7e 3902 my $pfamily = PVE::Tools::get_host_address_family($nodename);
91152441
WB
3903 my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily);
3904 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
4d316a63
AL
3905
3906 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3907 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3908 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3909
91152441
WB
3910 my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
3911 $spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
943340a6 3912
4df98f2f
TL
3913 my $spice_enhancement_str = $conf->{spice_enhancements} // '';
3914 my $spice_enhancement = parse_property_string($spice_enhancements_fmt, $spice_enhancement_str);
caab114a
TL
3915 if ($spice_enhancement->{foldersharing}) {
3916 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3917 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3918 }
c4df18db 3919
caab114a 3920 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
4df98f2f
TL
3921 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}"
3922 if $spice_enhancement->{videostreaming};
3923
caab114a 3924 push @$devices, '-spice', "$spice_opts";
1011b570
DM
3925 }
3926
8d9ae0d2
DM
3927 # enable balloon by default, unless explicitly disabled
3928 if (!defined($conf->{balloon}) || $conf->{balloon}) {
3326ae19 3929 my $pciaddr = print_pci_addr("balloon0", $bridges, $arch, $machine_type);
c70e4ec3
AD
3930 my $ballooncmd = "virtio-balloon-pci,id=balloon0$pciaddr";
3931 $ballooncmd .= ",free-page-reporting=on" if min_version($machine_version, 6, 2);
3932 push @$devices, '-device', $ballooncmd;
8d9ae0d2 3933 }
1e3baf05 3934
0ea9541d
DM
3935 if ($conf->{watchdog}) {
3936 my $wdopts = parse_watchdog($conf->{watchdog});
3326ae19 3937 my $pciaddr = print_pci_addr("watchdog", $bridges, $arch, $machine_type);
0a40e8ea 3938 my $watchdog = $wdopts->{model} || 'i6300esb';
5bdcf937
AD
3939 push @$devices, '-device', "$watchdog$pciaddr";
3940 push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
0ea9541d
DM
3941 }
3942
1e3baf05 3943 my $vollist = [];
941e0c42 3944 my $scsicontroller = {};
26ee04b6 3945 my $ahcicontroller = {};
cdd20088 3946 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : $defaults->{scsihw};
1e3baf05 3947
5881b913
DM
3948 # Add iscsi initiator name if available
3949 if (my $initiator = get_initiator_name()) {
3950 push @$devices, '-iscsi', "initiator-name=$initiator";
3951 }
3952
912792e2 3953 PVE::QemuConfig->foreach_volume($conf, sub {
1e3baf05
DM
3954 my ($ds, $drive) = @_;
3955
ff1a2432 3956 if (PVE::Storage::parse_volume_id($drive->{file}, 1)) {
3f11f0d7 3957 check_volume_storage_type($storecfg, $drive->{file});
1e3baf05 3958 push @$vollist, $drive->{file};
ff1a2432 3959 }
afdb31d5 3960
4dcce9ee
TL
3961 # ignore efidisk here, already added in bios/fw handling code above
3962 return if $drive->{interface} eq 'efidisk';
f9dde219
SR
3963 # similar for TPM
3964 return if $drive->{interface} eq 'tpmstate';
4dcce9ee 3965
1e3baf05 3966 $use_virtio = 1 if $ds =~ m/^virtio/;
3b408e82 3967
2141a802 3968 $drive->{bootindex} = $bootorder->{$ds} if $bootorder->{$ds};
3b408e82 3969
2f6f002c 3970 if ($drive->{interface} eq 'virtio'){
51f492cd
AD
3971 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread};
3972 }
3973
2f6f002c 3974 if ($drive->{interface} eq 'scsi') {
cdd20088 3975
ee034f5c 3976 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
6731a4cf 3977
b8fb1c03
SR
3978 die "scsi$drive->{index}: machine version 4.1~pve2 or higher is required to use more than 14 SCSI disks\n"
3979 if $drive->{index} > 13 && !&$version_guard(4, 1, 2);
3980
3326ae19 3981 my $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $machine_type);
a1b7d579 3982 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
fc8b40fd
AD
3983
3984 my $iothread = '';
3985 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{iothread}){
3986 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3987 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
e7a5104d 3988 } elsif ($drive->{iothread}) {
d80ad18c
MH
3989 log_warn(
3990 "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n"
3991 );
fc8b40fd
AD
3992 }
3993
6e11f143
AD
3994 my $queues = '';
3995 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{queues}){
3996 $queues = ",num_queues=$drive->{queues}";
370b05e7 3997 }
6e11f143 3998
4df98f2f
TL
3999 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues"
4000 if !$scsicontroller->{$controller};
cdd20088 4001 $scsicontroller->{$controller}=1;
2f6f002c 4002 }
3b408e82 4003
26ee04b6 4004 if ($drive->{interface} eq 'sata') {
2f6f002c 4005 my $controller = int($drive->{index} / $PVE::QemuServer::Drive::MAX_SATA_DISKS);
3326ae19 4006 my $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
4df98f2f
TL
4007 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
4008 if !$ahcicontroller->{$controller};
2f6f002c 4009 $ahcicontroller->{$controller}=1;
26ee04b6 4010 }
46f58b5f 4011
5921764c
SR
4012 my $pbs_conf = $pbs_backing->{$ds};
4013 my $pbs_name = undef;
4014 if ($pbs_conf) {
4015 $pbs_name = "drive-$ds-pbs";
4016 push @$devices, '-blockdev', print_pbs_blockdev($pbs_conf, $pbs_name);
4017 }
4018
6d5673c3
SR
4019 my $drive_cmd = print_drive_commandline_full(
4020 $storecfg, $vmid, $drive, $pbs_name, min_version($kvmver, 6, 0));
3dc33a72
FG
4021
4022 # extra protection for templates, but SATA and IDE don't support it..
75748d44 4023 $drive_cmd .= ',readonly=on' if drive_is_read_only($conf, $drive);
4ef13a7f 4024
15b21acc 4025 push @$devices, '-drive',$drive_cmd;
4df98f2f
TL
4026 push @$devices, '-device', print_drivedevice_full(
4027 $storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
1e3baf05
DM
4028 });
4029
cc4d6182 4030 for (my $i = 0; $i < $MAX_NETS; $i++) {
2141a802
SR
4031 my $netname = "net$i";
4032
4033 next if !$conf->{$netname};
4034 my $d = parse_net($conf->{$netname});
d0a86b24 4035 next if !$d;
1e3baf05 4036
d0a86b24 4037 $use_virtio = 1 if $d->{model} eq 'virtio';
1e3baf05 4038
2141a802 4039 $d->{bootindex} = $bootorder->{$netname} if $bootorder->{$netname};
1e3baf05 4040
2141a802 4041 my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, $netname);
d0a86b24 4042 push @$devices, '-netdev', $netdevfull;
5bdcf937 4043
d0a86b24 4044 my $netdevicefull = print_netdevice_full(
2141a802 4045 $vmid, $conf, $d, $netname, $bridges, $use_old_bios_files, $arch, $machine_type);
4df98f2f 4046
d0a86b24 4047 push @$devices, '-device', $netdevicefull;
5bdcf937 4048 }
1e3baf05 4049
6dbcb073 4050 if ($conf->{ivshmem}) {
4df98f2f 4051 my $ivshmem = parse_property_string($ivshmem_fmt, $conf->{ivshmem});
e3c27a6a 4052
6dbcb073
DC
4053 my $bus;
4054 if ($q35) {
4055 $bus = print_pcie_addr("ivshmem");
4056 } else {
4057 $bus = print_pci_addr("ivshmem", $bridges, $arch, $machine_type);
4058 }
e3c27a6a
TL
4059
4060 my $ivshmem_name = $ivshmem->{name} // $vmid;
4061 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
4062
6dbcb073 4063 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
4df98f2f
TL
4064 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path"
4065 .",size=$ivshmem->{size}M";
6dbcb073
DC
4066 }
4067
2513b862
DC
4068 # pci.4 is nested in pci.1
4069 $bridges->{1} = 1 if $bridges->{4};
4070
3326ae19
TL
4071 if (!$q35) { # add pci bridges
4072 if (min_version($machine_version, 2, 3)) {
fc79e813
AD
4073 $bridges->{1} = 1;
4074 $bridges->{2} = 1;
4075 }
6731a4cf 4076 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
2513b862
DC
4077 }
4078
4079 for my $k (sort {$b cmp $a} keys %$bridges) {
4080 next if $q35 && $k < 4; # q35.cfg already includes bridges up to 3
13d68979
SR
4081
4082 my $k_name = $k;
4083 if ($k == 2 && $legacy_igd) {
4084 $k_name = "$k-igd";
4085 }
3326ae19 4086 my $pciaddr = print_pci_addr("pci.$k_name", undef, $arch, $machine_type);
2513b862 4087 my $devstr = "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr";
3326ae19
TL
4088
4089 if ($q35) { # add after -readconfig pve-q35.cfg
2513b862
DC
4090 splice @$devices, 2, 0, '-device', $devstr;
4091 } else {
4092 unshift @$devices, '-device', $devstr if $k > 0;
f8e83f05 4093 }
19672434
DM
4094 }
4095
ac0077cc
SR
4096 if (!$kvm) {
4097 push @$machineFlags, 'accel=tcg';
4098 }
4099
e5a6919c
FE
4100 push @$machineFlags, 'smm=off' if should_disable_smm($conf, $vga);
4101
ac0077cc
SR
4102 my $machine_type_min = $machine_type;
4103 if ($add_pve_version) {
4104 $machine_type_min =~ s/\+pve\d+$//;
4105 $machine_type_min .= "+pve$required_pve_version";
4106 }
4107 push @$machineFlags, "type=${machine_type_min}";
4108
5bdcf937 4109 push @$cmd, @$devices;
2f6f002c
TL
4110 push @$cmd, '-rtc', join(',', @$rtcFlags) if scalar(@$rtcFlags);
4111 push @$cmd, '-machine', join(',', @$machineFlags) if scalar(@$machineFlags);
4112 push @$cmd, '-global', join(',', @$globalFlags) if scalar(@$globalFlags);
8c559505 4113
7ceade4c
DC
4114 if (my $vmstate = $conf->{vmstate}) {
4115 my $statepath = PVE::Storage::path($storecfg, $vmstate);
24d1f93a 4116 push @$vollist, $vmstate;
7ceade4c 4117 push @$cmd, '-loadstate', $statepath;
b85666cf 4118 print "activating and using '$vmstate' as vmstate\n";
7ceade4c
DC
4119 }
4120
85fcf79e
FG
4121 if (PVE::QemuConfig->is_template($conf)) {
4122 # needed to workaround base volumes being read-only
4123 push @$cmd, '-snapshot';
4124 }
4125
76350670
DC
4126 # add custom args
4127 if ($conf->{args}) {
4128 my $aa = PVE::Tools::split_args($conf->{args});
4129 push @$cmd, @$aa;
4130 }
4131
1d794448 4132 return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
1e3baf05 4133}
19672434 4134
05853188
SR
4135sub check_rng_source {
4136 my ($source) = @_;
4137
4138 # mostly relevant for /dev/hwrng, but doesn't hurt to check others too
4139 die "cannot create VirtIO RNG device: source file '$source' doesn't exist\n"
4140 if ! -e $source;
4141
4142 my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
4143 if ($source eq '/dev/hwrng' && file_read_firstline($rng_current) eq 'none') {
4df98f2f
TL
4144 # Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
4145 # be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
4146 die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
4147 ." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
4148 ." to the host.\n";
05853188
SR
4149 }
4150}
4151
943340a6 4152sub spice_port {
1011b570 4153 my ($vmid) = @_;
943340a6 4154
0a13e08e 4155 my $res = mon_cmd($vmid, 'query-spice');
943340a6
DM
4156
4157 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
1011b570
DM
4158}
4159
86fdcfb2
DA
4160sub vm_devices_list {
4161 my ($vmid) = @_;
4162
0a13e08e 4163 my $res = mon_cmd($vmid, 'query-pci');
f721624b 4164 my $devices_to_check = [];
ceea9078
DM
4165 my $devices = {};
4166 foreach my $pcibus (@$res) {
f721624b
DC
4167 push @$devices_to_check, @{$pcibus->{devices}},
4168 }
4169
4170 while (@$devices_to_check) {
4171 my $to_check = [];
4172 for my $d (@$devices_to_check) {
4173 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4174 next if !$d->{'pci_bridge'};
4175
4176 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices}});
4177 push @$to_check, @{$d->{'pci_bridge'}->{devices}};
f78cc802 4178 }
f721624b 4179 $devices_to_check = $to_check;
f78cc802
AD
4180 }
4181
0a13e08e 4182 my $resblock = mon_cmd($vmid, 'query-block');
f78cc802
AD
4183 foreach my $block (@$resblock) {
4184 if($block->{device} =~ m/^drive-(\S+)/){
4185 $devices->{$1} = 1;
1dc4f496
DM
4186 }
4187 }
86fdcfb2 4188
0a13e08e 4189 my $resmice = mon_cmd($vmid, 'query-mice');
3d7389fe
DM
4190 foreach my $mice (@$resmice) {
4191 if ($mice->{name} eq 'QEMU HID Tablet') {
4192 $devices->{tablet} = 1;
4193 last;
4194 }
4195 }
4196
deb091c5
DC
4197 # for usb devices there is no query-usb
4198 # but we can iterate over the entries in
4199 # qom-list path=/machine/peripheral
0a13e08e 4200 my $resperipheral = mon_cmd($vmid, 'qom-list', path => '/machine/peripheral');
deb091c5
DC
4201 foreach my $per (@$resperipheral) {
4202 if ($per->{name} =~ m/^usb\d+$/) {
4203 $devices->{$per->{name}} = 1;
4204 }
4205 }
4206
1dc4f496 4207 return $devices;
86fdcfb2
DA
4208}
4209
ec21aa11 4210sub vm_deviceplug {
d559309f 4211 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
ae57f6b3 4212
3392d6ca 4213 my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
db656e5f 4214
95d6343b
DA
4215 my $devices_list = vm_devices_list($vmid);
4216 return 1 if defined($devices_list->{$deviceid});
4217
4df98f2f
TL
4218 # add PCI bridge if we need it for the device
4219 qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
fee46675 4220
3d7389fe 4221 if ($deviceid eq 'tablet') {
d559309f 4222 qemu_deviceadd($vmid, print_tabletdevice_full($conf, $arch));
d559309f 4223 } elsif ($deviceid eq 'keyboard') {
d559309f 4224 qemu_deviceadd($vmid, print_keyboarddevice_full($conf, $arch));
4eb68604 4225 } elsif ($deviceid =~ m/^usb(\d+)$/) {
f745762b 4226 die "usb hotplug currently not reliable\n";
50bbe377
TL
4227 # since we can't reliably hot unplug all added usb devices and usb
4228 # passthrough breaks live migration we disable usb hotplugging for now
4229 #qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
fee46675 4230 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
22de899a
AD
4231 qemu_iothread_add($vmid, $deviceid, $device);
4232
3326ae19
TL
4233 qemu_driveadd($storecfg, $vmid, $device);
4234 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
fee46675 4235
3326ae19 4236 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
4237 eval { qemu_deviceaddverify($vmid, $deviceid); };
4238 if (my $err = $@) {
63c2da2f
DM
4239 eval { qemu_drivedel($vmid, $deviceid); };
4240 warn $@ if $@;
fee46675 4241 die $err;
5e5dcb73 4242 }
2733141c 4243 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3326ae19
TL
4244 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
4245 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
a1b7d579 4246 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
2733141c 4247
3326ae19 4248 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
fee46675 4249
fc8b40fd
AD
4250 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread}) {
4251 qemu_iothread_add($vmid, $deviceid, $device);
4252 $devicefull .= ",iothread=iothread-$deviceid";
4253 }
4254
6e11f143
AD
4255 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues}) {
4256 $devicefull .= ",num_queues=$device->{queues}";
4257 }
4258
3326ae19
TL
4259 qemu_deviceadd($vmid, $devicefull);
4260 qemu_deviceaddverify($vmid, $deviceid);
fee46675 4261 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
d559309f 4262 qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device, $arch, $machine_type);
fee46675 4263 qemu_driveadd($storecfg, $vmid, $device);
a1b7d579 4264
acfc6ef8 4265 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, undef, $arch, $machine_type);
fee46675
DM
4266 eval { qemu_deviceadd($vmid, $devicefull); };
4267 if (my $err = $@) {
63c2da2f
DM
4268 eval { qemu_drivedel($vmid, $deviceid); };
4269 warn $@ if $@;
fee46675 4270 die $err;
a4f091a0 4271 }
fee46675 4272 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
d1c1af4b 4273 return if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
8718099c 4274
3392d6ca 4275 my $machine_type = PVE::QemuServer::Machine::qemu_machine_pxe($vmid, $conf);
95d3be58
DC
4276 my $use_old_bios_files = undef;
4277 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
8718099c 4278
4df98f2f
TL
4279 my $netdevicefull = print_netdevice_full(
4280 $vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
95d3be58 4281 qemu_deviceadd($vmid, $netdevicefull);
79046fd1
DC
4282 eval {
4283 qemu_deviceaddverify($vmid, $deviceid);
4284 qemu_set_link_status($vmid, $deviceid, !$device->{link_down});
4285 };
fee46675
DM
4286 if (my $err = $@) {
4287 eval { qemu_netdevdel($vmid, $deviceid); };
4288 warn $@ if $@;
4289 die $err;
95d3be58 4290 }
fee46675 4291 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
40f28a9f 4292 my $bridgeid = $2;
d559309f 4293 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
40f28a9f 4294 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
a1b7d579 4295
40f28a9f 4296 qemu_deviceadd($vmid, $devicefull);
fee46675 4297 qemu_deviceaddverify($vmid, $deviceid);
fee46675 4298 } else {
a1b7d579 4299 die "can't hotplug device '$deviceid'\n";
40f28a9f
AD
4300 }
4301
5e5dcb73 4302 return 1;
a4dea331
DA
4303}
4304
3eec5767 4305# fixme: this should raise exceptions on error!
ec21aa11 4306sub vm_deviceunplug {
f19d1c47 4307 my ($vmid, $conf, $deviceid) = @_;
873c2d69 4308
95d6343b
DA
4309 my $devices_list = vm_devices_list($vmid);
4310 return 1 if !defined($devices_list->{$deviceid});
4311
2141a802
SR
4312 my $bootdisks = PVE::QemuServer::Drive::get_bootdisks($conf);
4313 die "can't unplug bootdisk '$deviceid'\n" if grep {$_ eq $deviceid} @$bootdisks;
63c2da2f 4314
d559309f 4315 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
3d7389fe 4316 qemu_devicedel($vmid, $deviceid);
4eb68604 4317 } elsif ($deviceid =~ m/^usb\d+$/) {
f745762b 4318 die "usb hotplug currently not reliable\n";
50bbe377
TL
4319 # when unplugging usb devices this way, there may be remaining usb
4320 # controllers/hubs so we disable it for now
4321 #qemu_devicedel($vmid, $deviceid);
4322 #qemu_devicedelverify($vmid, $deviceid);
63c2da2f 4323 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
9a66c311 4324 my $device = parse_drive($deviceid, $conf->{$deviceid});
f19d1c47 4325
a8d0fec3
TL
4326 qemu_devicedel($vmid, $deviceid);
4327 qemu_devicedelverify($vmid, $deviceid);
4328 qemu_drivedel($vmid, $deviceid);
9a66c311 4329 qemu_iothread_del($vmid, $deviceid, $device);
2733141c 4330 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
63c2da2f 4331 qemu_devicedel($vmid, $deviceid);
8ce30dde 4332 qemu_devicedelverify($vmid, $deviceid);
63c2da2f 4333 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
9a66c311 4334 my $device = parse_drive($deviceid, $conf->{$deviceid});
cfc817c7 4335
a8d0fec3 4336 qemu_devicedel($vmid, $deviceid);
52b361af 4337 qemu_devicedelverify($vmid, $deviceid);
a8d0fec3 4338 qemu_drivedel($vmid, $deviceid);
a1b7d579 4339 qemu_deletescsihw($conf, $vmid, $deviceid);
8ce30dde 4340
9a66c311
FG
4341 qemu_iothread_del($vmid, "virtioscsi$device->{index}", $device)
4342 if $conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single');
63c2da2f 4343 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
a8d0fec3
TL
4344 qemu_devicedel($vmid, $deviceid);
4345 qemu_devicedelverify($vmid, $deviceid);
4346 qemu_netdevdel($vmid, $deviceid);
63c2da2f
DM
4347 } else {
4348 die "can't unplug device '$deviceid'\n";
2630d2a9
DA
4349 }
4350
5e5dcb73
DA
4351 return 1;
4352}
4353
4354sub qemu_deviceadd {
4355 my ($vmid, $devicefull) = @_;
873c2d69 4356
d695b5b7
AD
4357 $devicefull = "driver=".$devicefull;
4358 my %options = split(/[=,]/, $devicefull);
f19d1c47 4359
0a13e08e 4360 mon_cmd($vmid, "device_add" , %options);
5e5dcb73 4361}
afdb31d5 4362
5e5dcb73 4363sub qemu_devicedel {
fee46675 4364 my ($vmid, $deviceid) = @_;
63c2da2f 4365
0a13e08e 4366 my $ret = mon_cmd($vmid, "device_del", id => $deviceid);
5e5dcb73
DA
4367}
4368
22de899a 4369sub qemu_iothread_add {
a8d0fec3 4370 my ($vmid, $deviceid, $device) = @_;
22de899a
AD
4371
4372 if ($device->{iothread}) {
4373 my $iothreads = vm_iothreads_list($vmid);
4374 qemu_objectadd($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4375 }
4376}
4377
4378sub qemu_iothread_del {
a8d0fec3 4379 my ($vmid, $deviceid, $device) = @_;
22de899a 4380
22de899a
AD
4381 if ($device->{iothread}) {
4382 my $iothreads = vm_iothreads_list($vmid);
4383 qemu_objectdel($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4384 }
4385}
4386
4d3f29ed 4387sub qemu_objectadd {
a8d0fec3 4388 my ($vmid, $objectid, $qomtype) = @_;
4d3f29ed 4389
0a13e08e 4390 mon_cmd($vmid, "object-add", id => $objectid, "qom-type" => $qomtype);
4d3f29ed
AD
4391
4392 return 1;
4393}
4394
4395sub qemu_objectdel {
a8d0fec3 4396 my ($vmid, $objectid) = @_;
4d3f29ed 4397
0a13e08e 4398 mon_cmd($vmid, "object-del", id => $objectid);
4d3f29ed
AD
4399
4400 return 1;
4401}
4402
5e5dcb73 4403sub qemu_driveadd {
fee46675 4404 my ($storecfg, $vmid, $device) = @_;
5e5dcb73 4405
6d5673c3
SR
4406 my $kvmver = get_running_qemu_version($vmid);
4407 my $io_uring = min_version($kvmver, 6, 0);
4408 my $drive = print_drive_commandline_full($storecfg, $vmid, $device, undef, $io_uring);
7a69fc3c 4409 $drive =~ s/\\/\\\\/g;
0a13e08e 4410 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_add auto \"$drive\"");
fee46675 4411
5e5dcb73 4412 # If the command succeeds qemu prints: "OK"
fee46675
DM
4413 return 1 if $ret =~ m/OK/s;
4414
4415 die "adding drive failed: $ret\n";
5e5dcb73 4416}
afdb31d5 4417
5e5dcb73 4418sub qemu_drivedel {
a8d0fec3 4419 my ($vmid, $deviceid) = @_;
873c2d69 4420
0a13e08e 4421 my $ret = PVE::QemuServer::Monitor::hmp_cmd($vmid, "drive_del drive-$deviceid");
5e5dcb73 4422 $ret =~ s/^\s+//;
a1b7d579 4423
63c2da2f 4424 return 1 if $ret eq "";
a1b7d579 4425
63c2da2f 4426 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
a1b7d579
DM
4427 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4428
63c2da2f 4429 die "deleting drive $deviceid failed : $ret\n";
5e5dcb73 4430}
f19d1c47 4431
5e5dcb73 4432sub qemu_deviceaddverify {
fee46675 4433 my ($vmid, $deviceid) = @_;
873c2d69 4434
5e5dcb73
DA
4435 for (my $i = 0; $i <= 5; $i++) {
4436 my $devices_list = vm_devices_list($vmid);
4437 return 1 if defined($devices_list->{$deviceid});
4438 sleep 1;
afdb31d5 4439 }
fee46675
DM
4440
4441 die "error on hotplug device '$deviceid'\n";
5e5dcb73 4442}
afdb31d5 4443
5e5dcb73
DA
4444
4445sub qemu_devicedelverify {
63c2da2f
DM
4446 my ($vmid, $deviceid) = @_;
4447
a1b7d579 4448 # need to verify that the device is correctly removed as device_del
63c2da2f 4449 # is async and empty return is not reliable
5e5dcb73 4450
5e5dcb73
DA
4451 for (my $i = 0; $i <= 5; $i++) {
4452 my $devices_list = vm_devices_list($vmid);
4453 return 1 if !defined($devices_list->{$deviceid});
4454 sleep 1;
afdb31d5 4455 }
63c2da2f
DM
4456
4457 die "error on hot-unplugging device '$deviceid'\n";
873c2d69
DA
4458}
4459
cdd20088 4460sub qemu_findorcreatescsihw {
d559309f 4461 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
cfc817c7 4462
ee034f5c 4463 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
2733141c
AD
4464
4465 my $scsihwid="$controller_prefix$controller";
cfc817c7
DA
4466 my $devices_list = vm_devices_list($vmid);
4467
a8d0fec3 4468 if (!defined($devices_list->{$scsihwid})) {
d559309f 4469 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
cfc817c7 4470 }
fee46675 4471
cfc817c7
DA
4472 return 1;
4473}
4474
8ce30dde
AD
4475sub qemu_deletescsihw {
4476 my ($conf, $vmid, $opt) = @_;
4477
4478 my $device = parse_drive($opt, $conf->{$opt});
4479
a1511b3c 4480 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
2733141c
AD
4481 vm_deviceunplug($vmid, $conf, "virtioscsi$device->{index}");
4482 return 1;
4483 }
4484
ee034f5c 4485 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
8ce30dde
AD
4486
4487 my $devices_list = vm_devices_list($vmid);
4488 foreach my $opt (keys %{$devices_list}) {
e0fd2b2f
FE
4489 if (is_valid_drivename($opt)) {
4490 my $drive = parse_drive($opt, $conf->{$opt});
a8d0fec3 4491 if ($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
8ce30dde
AD
4492 return 1;
4493 }
4494 }
4495 }
4496
4497 my $scsihwid="scsihw$controller";
4498
4499 vm_deviceunplug($vmid, $conf, $scsihwid);
4500
4501 return 1;
4502}
4503
281fedb3 4504sub qemu_add_pci_bridge {
d559309f 4505 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
40f28a9f
AD
4506
4507 my $bridges = {};
281fedb3
DM
4508
4509 my $bridgeid;
4510
d559309f 4511 print_pci_addr($device, $bridges, $arch, $machine_type);
40f28a9f
AD
4512
4513 while (my ($k, $v) = each %$bridges) {
4514 $bridgeid = $k;
4515 }
fee46675 4516 return 1 if !defined($bridgeid) || $bridgeid < 1;
281fedb3 4517
40f28a9f
AD
4518 my $bridge = "pci.$bridgeid";
4519 my $devices_list = vm_devices_list($vmid);
4520
281fedb3 4521 if (!defined($devices_list->{$bridge})) {
d559309f 4522 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
40f28a9f 4523 }
281fedb3 4524
40f28a9f
AD
4525 return 1;
4526}
4527
25088687
DM
4528sub qemu_set_link_status {
4529 my ($vmid, $device, $up) = @_;
4530
0a13e08e 4531 mon_cmd($vmid, "set_link", name => $device,
25088687
DM
4532 up => $up ? JSON::true : JSON::false);
4533}
4534
2630d2a9 4535sub qemu_netdevadd {
d559309f 4536 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
2630d2a9 4537
d559309f 4538 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
73aa03b8 4539 my %options = split(/[=,]/, $netdev);
2630d2a9 4540
bf5aef9b
DC
4541 if (defined(my $vhost = $options{vhost})) {
4542 $options{vhost} = JSON::boolean(PVE::JSONSchema::parse_boolean($vhost));
4543 }
4544
4545 if (defined(my $queues = $options{queues})) {
4546 $options{queues} = $queues + 0;
4547 }
4548
0a13e08e 4549 mon_cmd($vmid, "netdev_add", %options);
73aa03b8 4550 return 1;
2630d2a9
DA
4551}
4552
4553sub qemu_netdevdel {
4554 my ($vmid, $deviceid) = @_;
4555
0a13e08e 4556 mon_cmd($vmid, "netdev_del", id => $deviceid);
2630d2a9
DA
4557}
4558
16521d63 4559sub qemu_usb_hotplug {
d559309f 4560 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
16521d63
DC
4561
4562 return if !$device;
4563
4564 # remove the old one first
4565 vm_deviceunplug($vmid, $conf, $deviceid);
4566
4567 # check if xhci controller is necessary and available
4568 if ($device->{usb3}) {
4569
4570 my $devicelist = vm_devices_list($vmid);
4571
4572 if (!$devicelist->{xhci}) {
d559309f 4573 my $pciaddr = print_pci_addr("xhci", undef, $arch, $machine_type);
16521d63
DC
4574 qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
4575 }
4576 }
4577 my $d = parse_usb_device($device->{host});
4578 $d->{usb3} = $device->{usb3};
4579
4580 # add the new one
d559309f 4581 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
16521d63
DC
4582}
4583
838776ab 4584sub qemu_cpu_hotplug {
8edc9c08 4585 my ($vmid, $conf, $vcpus) = @_;
838776ab 4586
3392d6ca 4587 my $machine_type = PVE::QemuServer::Machine::get_current_qemu_machine($vmid);
1e881b75 4588
8edc9c08
AD
4589 my $sockets = 1;
4590 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4591 $sockets = $conf->{sockets} if $conf->{sockets};
4592 my $cores = $conf->{cores} || 1;
4593 my $maxcpus = $sockets * $cores;
838776ab 4594
8edc9c08 4595 $vcpus = $maxcpus if !$vcpus;
3a11fadb 4596
8edc9c08
AD
4597 die "you can't add more vcpus than maxcpus\n"
4598 if $vcpus > $maxcpus;
3a11fadb 4599
8edc9c08 4600 my $currentvcpus = $conf->{vcpus} || $maxcpus;
1e881b75 4601
eba3e64d 4602 if ($vcpus < $currentvcpus) {
1e881b75 4603
2ea5fb7e 4604 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
1e881b75
AD
4605
4606 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4607 qemu_devicedel($vmid, "cpu$i");
4608 my $retry = 0;
4609 my $currentrunningvcpus = undef;
4610 while (1) {
65af8c31 4611 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
1e881b75 4612 last if scalar(@{$currentrunningvcpus}) == $i-1;
961af8a3 4613 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
1e881b75
AD
4614 $retry++;
4615 sleep 1;
4616 }
4617 #update conf after each succesfull cpu unplug
4618 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4619 PVE::QemuConfig->write_config($vmid, $conf);
4620 }
4621 } else {
961af8a3 4622 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
1e881b75
AD
4623 }
4624
4625 return;
4626 }
838776ab 4627
65af8c31 4628 my $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
961af8a3 4629 die "vcpus in running vm does not match its configuration\n"
8edc9c08 4630 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
838776ab 4631
2ea5fb7e 4632 if (PVE::QemuServer::Machine::machine_version($machine_type, 2, 7)) {
eba3e64d
AD
4633
4634 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4635 my $cpustr = print_cpu_device($conf, $i);
4636 qemu_deviceadd($vmid, $cpustr);
4637
4638 my $retry = 0;
4639 my $currentrunningvcpus = undef;
4640 while (1) {
65af8c31 4641 $currentrunningvcpus = mon_cmd($vmid, "query-cpus-fast");
eba3e64d 4642 last if scalar(@{$currentrunningvcpus}) == $i;
961af8a3 4643 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
eba3e64d
AD
4644 sleep 1;
4645 $retry++;
4646 }
4647 #update conf after each succesfull cpu hotplug
4648 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4649 PVE::QemuConfig->write_config($vmid, $conf);
4650 }
4651 } else {
4652
4653 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
0a13e08e 4654 mon_cmd($vmid, "cpu-add", id => int($i));
eba3e64d 4655 }
838776ab
AD
4656 }
4657}
4658
affd2f88 4659sub qemu_block_set_io_throttle {
277ca170
WB
4660 my ($vmid, $deviceid,
4661 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
9196a8ec
WB
4662 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4663 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4664 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
affd2f88 4665
f3f323a3
AD
4666 return if !check_running($vmid) ;
4667
0a13e08e 4668 mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
277ca170
WB
4669 bps => int($bps),
4670 bps_rd => int($bps_rd),
4671 bps_wr => int($bps_wr),
4672 iops => int($iops),
4673 iops_rd => int($iops_rd),
4674 iops_wr => int($iops_wr),
4675 bps_max => int($bps_max),
4676 bps_rd_max => int($bps_rd_max),
4677 bps_wr_max => int($bps_wr_max),
4678 iops_max => int($iops_max),
4679 iops_rd_max => int($iops_rd_max),
9196a8ec
WB
4680 iops_wr_max => int($iops_wr_max),
4681 bps_max_length => int($bps_max_length),
4682 bps_rd_max_length => int($bps_rd_max_length),
4683 bps_wr_max_length => int($bps_wr_max_length),
4684 iops_max_length => int($iops_max_length),
4685 iops_rd_max_length => int($iops_rd_max_length),
4686 iops_wr_max_length => int($iops_wr_max_length),
277ca170 4687 );
f3f323a3 4688
affd2f88
AD
4689}
4690
c1175c92
AD
4691sub qemu_block_resize {
4692 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4693
ed221350 4694 my $running = check_running($vmid);
c1175c92 4695
7246e8f9 4696 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
c1175c92
AD
4697
4698 return if !$running;
4699
375db731
FE
4700 my $padding = (1024 - $size % 1024) % 1024;
4701 $size = $size + $padding;
4702
190c8461
SR
4703 mon_cmd(
4704 $vmid,
4705 "block_resize",
4706 device => $deviceid,
4707 size => int($size),
4708 timeout => 60,
4709 );
c1175c92
AD
4710}
4711
1ab0057c
AD
4712sub qemu_volume_snapshot {
4713 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4714
ed221350 4715 my $running = check_running($vmid);
1ab0057c 4716
9d83932d 4717 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
0a13e08e 4718 mon_cmd($vmid, 'blockdev-snapshot-internal-sync', device => $deviceid, name => $snap);
e5eaa028
WL
4719 } else {
4720 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4721 }
1ab0057c
AD
4722}
4723
fc46aff9
AD
4724sub qemu_volume_snapshot_delete {
4725 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4726
ed221350 4727 my $running = check_running($vmid);
fc46aff9 4728
a2f1554b
AD
4729 if($running) {
4730
4731 $running = undef;
4732 my $conf = PVE::QemuConfig->load_config($vmid);
912792e2 4733 PVE::QemuConfig->foreach_volume($conf, sub {
a2f1554b
AD
4734 my ($ds, $drive) = @_;
4735 $running = 1 if $drive->{file} eq $volid;
4736 });
4737 }
4738
9d83932d 4739 if ($running && do_snapshots_with_qemu($storecfg, $volid, $deviceid)) {
0a13e08e 4740 mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync', device => $deviceid, name => $snap);
1ef7592f
AD
4741 } else {
4742 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4743 }
fc46aff9
AD
4744}
4745
264e519f 4746sub set_migration_caps {
27a5be53 4747 my ($vmid, $savevm) = @_;
a89fded1 4748
acc10e51
SR
4749 my $qemu_support = eval { mon_cmd($vmid, "query-proxmox-support") };
4750
27a5be53
SR
4751 my $bitmap_prop = $savevm ? 'pbs-dirty-bitmap-savevm' : 'pbs-dirty-bitmap-migration';
4752 my $dirty_bitmaps = $qemu_support->{$bitmap_prop} ? 1 : 0;
4753
8b8345f3 4754 my $cap_ref = [];
a89fded1
AD
4755
4756 my $enabled_cap = {
8b8345f3 4757 "auto-converge" => 1,
0b0a47e8 4758 "xbzrle" => 1,
8b8345f3
DM
4759 "x-rdma-pin-all" => 0,
4760 "zero-blocks" => 0,
acc10e51 4761 "compress" => 0,
27a5be53 4762 "dirty-bitmaps" => $dirty_bitmaps,
a89fded1
AD
4763 };
4764
0a13e08e 4765 my $supported_capabilities = mon_cmd($vmid, "query-migrate-capabilities");
a89fded1 4766
8b8345f3 4767 for my $supported_capability (@$supported_capabilities) {
b463a3ce
SP
4768 push @$cap_ref, {
4769 capability => $supported_capability->{capability},
22430fa2
DM
4770 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4771 };
a89fded1
AD
4772 }
4773
0a13e08e 4774 mon_cmd($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
8b8345f3 4775}
a89fded1 4776
912792e2
FE
4777sub foreach_volid {
4778 my ($conf, $func, @param) = @_;
4779
4780 my $volhash = {};
4781
4782 my $test_volid = sub {
ae180b8f 4783 my ($key, $drive, $snapname) = @_;
912792e2 4784
ae180b8f 4785 my $volid = $drive->{file};
912792e2
FE
4786 return if !$volid;
4787
4788 $volhash->{$volid}->{cdrom} //= 1;
ae180b8f 4789 $volhash->{$volid}->{cdrom} = 0 if !drive_is_cdrom($drive);
912792e2 4790
ae180b8f 4791 my $replicate = $drive->{replicate} // 1;
912792e2
FE
4792 $volhash->{$volid}->{replicate} //= 0;
4793 $volhash->{$volid}->{replicate} = 1 if $replicate;
4794
4795 $volhash->{$volid}->{shared} //= 0;
ae180b8f 4796 $volhash->{$volid}->{shared} = 1 if $drive->{shared};
912792e2
FE
4797
4798 $volhash->{$volid}->{referenced_in_config} //= 0;
4799 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
4800
4801 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
4802 if defined($snapname);
ae180b8f
FE
4803
4804 my $size = $drive->{size};
4805 $volhash->{$volid}->{size} //= $size if $size;
4806
4807 $volhash->{$volid}->{is_vmstate} //= 0;
4808 $volhash->{$volid}->{is_vmstate} = 1 if $key eq 'vmstate';
4809
f9dde219
SR
4810 $volhash->{$volid}->{is_tpmstate} //= 0;
4811 $volhash->{$volid}->{is_tpmstate} = 1 if $key eq 'tpmstate0';
4812
ae180b8f
FE
4813 $volhash->{$volid}->{is_unused} //= 0;
4814 $volhash->{$volid}->{is_unused} = 1 if $key =~ /^unused\d+$/;
a6be63ac
FE
4815
4816 $volhash->{$volid}->{drivename} = $key if is_valid_drivename($key);
912792e2
FE
4817 };
4818
ae180b8f
FE
4819 my $include_opts = {
4820 extra_keys => ['vmstate'],
4821 include_unused => 1,
4822 };
4823
0b953b8e 4824 PVE::QemuConfig->foreach_volume_full($conf, $include_opts, $test_volid);
912792e2
FE
4825 foreach my $snapname (keys %{$conf->{snapshots}}) {
4826 my $snap = $conf->{snapshots}->{$snapname};
0b953b8e 4827 PVE::QemuConfig->foreach_volume_full($snap, $include_opts, $test_volid, $snapname);
912792e2
FE
4828 }
4829
4830 foreach my $volid (keys %$volhash) {
4831 &$func($volid, $volhash->{$volid}, @param);
4832 }
4833}
4834
81d95ae1 4835my $fast_plug_option = {
7498eb64 4836 'lock' => 1,
81d95ae1 4837 'name' => 1,
a1b7d579 4838 'onboot' => 1,
81d95ae1
DM
4839 'shares' => 1,
4840 'startup' => 1,
b0ec896e 4841 'description' => 1,
ec647db4 4842 'protection' => 1,
8cad5e9b 4843 'vmstatestorage' => 1,
9e784b11 4844 'hookscript' => 1,
b8e7068a 4845 'tags' => 1,
81d95ae1
DM
4846};
4847
71d9006b
AD
4848for my $opt (keys %$confdesc_cloudinit) {
4849 $fast_plug_option->{$opt} = 1;
4850};
4851
3a11fadb
DM
4852# hotplug changes in [PENDING]
4853# $selection hash can be used to only apply specified options, for
4854# example: { cores => 1 } (only apply changed 'cores')
4855# $errors ref is used to return error messages
c427973b 4856sub vmconfig_hotplug_pending {
3a11fadb 4857 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
c427973b 4858
8e90138a 4859 my $defaults = load_defaults();
045749f2
TL
4860 my $arch = get_vm_arch($conf);
4861 my $machine_type = get_vm_machine($conf, undef, $arch);
c427973b
DM
4862
4863 # commit values which do not have any impact on running VM first
3a11fadb
DM
4864 # Note: those option cannot raise errors, we we do not care about
4865 # $selection and always apply them.
4866
4867 my $add_error = sub {
4868 my ($opt, $msg) = @_;
4869 $errors->{$opt} = "hotplug problem - $msg";
4870 };
c427973b
DM
4871
4872 my $changes = 0;
4873 foreach my $opt (keys %{$conf->{pending}}) { # add/change
81d95ae1 4874 if ($fast_plug_option->{$opt}) {
c427973b
DM
4875 $conf->{$opt} = $conf->{pending}->{$opt};
4876 delete $conf->{pending}->{$opt};
4877 $changes = 1;
4878 }
4879 }
4880
4881 if ($changes) {
ffda963f 4882 PVE::QemuConfig->write_config($vmid, $conf);
c427973b
DM
4883 }
4884
b3c2bdd1 4885 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
c427973b 4886
5b65b00d 4887 my $cgroup = PVE::QemuServer::CGroup->new($vmid);
98bc3aeb 4888 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 4889 foreach my $opt (sort keys %$pending_delete_hash) {
3a11fadb 4890 next if $selection && !$selection->{$opt};
d321c4a9 4891 my $force = $pending_delete_hash->{$opt}->{force};
3a11fadb 4892 eval {
51a6f637
AD
4893 if ($opt eq 'hotplug') {
4894 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4895 } elsif ($opt eq 'tablet') {
b3c2bdd1 4896 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4897 if ($defaults->{tablet}) {
d559309f
WB
4898 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4899 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4900 if $arch eq 'aarch64';
3a11fadb 4901 } else {
d559309f
WB
4902 vm_deviceunplug($vmid, $conf, 'tablet');
4903 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4904 }
4eb68604 4905 } elsif ($opt =~ m/^usb\d+/) {
f745762b 4906 die "skip\n";
50bbe377
TL
4907 # since we cannot reliably hot unplug usb devices we are disabling it
4908 #die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4909 #vm_deviceunplug($vmid, $conf, $opt);
8edc9c08 4910 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4911 die "skip\n" if !$hotplug_features->{cpu};
8edc9c08 4912 qemu_cpu_hotplug($vmid, $conf, undef);
9c2f7069 4913 } elsif ($opt eq 'balloon') {
81d95ae1 4914 # enable balloon device is not hotpluggable
75b51053
DC
4915 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4916 # here we reset the ballooning value to memory
4917 my $balloon = $conf->{memory} || $defaults->{memory};
0a13e08e 4918 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
81d95ae1
DM
4919 } elsif ($fast_plug_option->{$opt}) {
4920 # do nothing
3eec5767 4921 } elsif ($opt =~ m/^net(\d+)$/) {
b3c2bdd1 4922 die "skip\n" if !$hotplug_features->{network};
3eec5767 4923 vm_deviceunplug($vmid, $conf, $opt);
74479ee9 4924 } elsif (is_valid_drivename($opt)) {
b3c2bdd1 4925 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
19120f99 4926 vm_deviceunplug($vmid, $conf, $opt);
3dc38fbb 4927 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4d3f29ed
AD
4928 } elsif ($opt =~ m/^memory$/) {
4929 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4930 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
c8effec3 4931 } elsif ($opt eq 'cpuunits') {
0d318453 4932 $cgroup->change_cpu_shares(undef);
58be00f1 4933 } elsif ($opt eq 'cpulimit') {
25de70ae 4934 $cgroup->change_cpu_quota(undef, undef); # reset, cgroup module can better decide values
3d7389fe 4935 } else {
e56beeda 4936 die "skip\n";
3d7389fe 4937 }
3a11fadb
DM
4938 };
4939 if (my $err = $@) {
e56beeda
DM
4940 &$add_error($opt, $err) if $err ne "skip\n";
4941 } else {
3a11fadb 4942 delete $conf->{$opt};
98bc3aeb 4943 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
3d7389fe 4944 }
3d7389fe
DM
4945 }
4946
4947 foreach my $opt (keys %{$conf->{pending}}) {
3a11fadb 4948 next if $selection && !$selection->{$opt};
3d7389fe 4949 my $value = $conf->{pending}->{$opt};
3a11fadb 4950 eval {
51a6f637
AD
4951 if ($opt eq 'hotplug') {
4952 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4953 } elsif ($opt eq 'tablet') {
b3c2bdd1 4954 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4955 if ($value == 1) {
d559309f
WB
4956 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4957 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4958 if $arch eq 'aarch64';
3a11fadb 4959 } elsif ($value == 0) {
d559309f
WB
4960 vm_deviceunplug($vmid, $conf, 'tablet');
4961 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4962 }
4eb68604 4963 } elsif ($opt =~ m/^usb\d+$/) {
f745762b 4964 die "skip\n";
50bbe377
TL
4965 # since we cannot reliably hot unplug usb devices we disable it for now
4966 #die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4967 #my $d = eval { parse_property_string($usbdesc->{format}, $value) };
4968 #die "skip\n" if !$d;
4969 #qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
8edc9c08 4970 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4971 die "skip\n" if !$hotplug_features->{cpu};
3a11fadb
DM
4972 qemu_cpu_hotplug($vmid, $conf, $value);
4973 } elsif ($opt eq 'balloon') {
81d95ae1 4974 # enable/disable balloning device is not hotpluggable
8fe689e7 4975 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
a1b7d579 4976 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
81d95ae1
DM
4977 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4978
3a11fadb 4979 # allow manual ballooning if shares is set to zero
4cc1efa6 4980 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
9c2f7069 4981 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
0a13e08e 4982 mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
9c2f7069 4983 }
a1b7d579 4984 } elsif ($opt =~ m/^net(\d+)$/) {
3eec5767 4985 # some changes can be done without hotplug
a1b7d579 4986 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
d559309f 4987 $vmid, $opt, $value, $arch, $machine_type);
74479ee9 4988 } elsif (is_valid_drivename($opt)) {
f9dde219 4989 die "skip\n" if $opt eq 'efidisk0' || $opt eq 'tpmstate0';
a05cff86 4990 # some changes can be done without hotplug
9ed7a77c
WB
4991 my $drive = parse_drive($opt, $value);
4992 if (drive_is_cloudinit($drive)) {
71d9006b 4993 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
9ed7a77c 4994 }
b3c2bdd1 4995 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
9e7bce2c 4996 $vmid, $opt, $value, $arch, $machine_type);
4d3f29ed
AD
4997 } elsif ($opt =~ m/^memory$/) { #dimms
4998 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4999 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
c8effec3 5000 } elsif ($opt eq 'cpuunits') {
6b7ef5e5 5001 my $new_cpuunits = PVE::CGroup::clamp_cpu_shares($conf->{pending}->{$opt}); #clamp
0d318453 5002 $cgroup->change_cpu_shares($new_cpuunits);
58be00f1 5003 } elsif ($opt eq 'cpulimit') {
c6f773b8 5004 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
5b65b00d 5005 $cgroup->change_cpu_quota($cpulimit, 100000);
74ea2c65
AD
5006 } elsif ($opt eq 'agent') {
5007 vmconfig_update_agent($conf, $opt, $value);
3a11fadb 5008 } else {
e56beeda 5009 die "skip\n"; # skip non-hot-pluggable options
3d7389fe 5010 }
3a11fadb
DM
5011 };
5012 if (my $err = $@) {
e56beeda
DM
5013 &$add_error($opt, $err) if $err ne "skip\n";
5014 } else {
3a11fadb
DM
5015 $conf->{$opt} = $value;
5016 delete $conf->{pending}->{$opt};
3d7389fe 5017 }
3d7389fe 5018 }
4df15a03 5019 PVE::QemuConfig->write_config($vmid, $conf);
94ec5e7c
AD
5020
5021 if($hotplug_features->{cloudinit}) {
5022 my $pending = PVE::QemuServer::Cloudinit::get_pending_config($conf, $vmid);
5023 my $regenerate = undef;
5024 for my $item (@$pending) {
5025 $regenerate = 1 if defined($item->{delete}) or defined($item->{pending});
5026 }
5027 PVE::QemuServer::vmconfig_update_cloudinit_drive($storecfg, $conf, $vmid) if $regenerate;
5028 }
c427973b 5029}
055d554d 5030
3dc38fbb
WB
5031sub try_deallocate_drive {
5032 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
5033
5034 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
5035 my $volid = $drive->{file};
5036 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
5037 my $sid = PVE::Storage::parse_volume_id($volid);
5038 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
cee01bcb
WB
5039
5040 # check if the disk is really unused
cee01bcb 5041 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
e0fd2b2f 5042 if PVE::QemuServer::Drive::is_volume_in_use($storecfg, $conf, $key, $volid);
cee01bcb 5043 PVE::Storage::vdisk_free($storecfg, $volid);
3dc38fbb 5044 return 1;
40b977f3
WL
5045 } else {
5046 # If vm is not owner of this disk remove from config
5047 return 1;
3dc38fbb
WB
5048 }
5049 }
5050
d1c1af4b 5051 return;
3dc38fbb
WB
5052}
5053
5054sub vmconfig_delete_or_detach_drive {
5055 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
5056
5057 my $drive = parse_drive($opt, $conf->{$opt});
5058
5059 my $rpcenv = PVE::RPCEnvironment::get();
5060 my $authuser = $rpcenv->get_user();
5061
5062 if ($force) {
5063 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
5064 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
5065 } else {
5066 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
5067 }
5068}
5069
98bc3aeb
OB
5070
5071
055d554d 5072sub vmconfig_apply_pending {
eb5e482d
OB
5073 my ($vmid, $conf, $storecfg, $errors) = @_;
5074
a644de29
OB
5075 return if !scalar(keys %{$conf->{pending}});
5076
eb5e482d
OB
5077 my $add_apply_error = sub {
5078 my ($opt, $msg) = @_;
5079 my $err_msg = "unable to apply pending change $opt : $msg";
5080 $errors->{$opt} = $err_msg;
5081 warn $err_msg;
5082 };
c427973b
DM
5083
5084 # cold plug
055d554d 5085
98bc3aeb 5086 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 5087 foreach my $opt (sort keys %$pending_delete_hash) {
fb4d1ba2 5088 my $force = $pending_delete_hash->{$opt}->{force};
eb5e482d 5089 eval {
3d48b95a
OB
5090 if ($opt =~ m/^unused/) {
5091 die "internal error";
5092 } elsif (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 5093 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
eb5e482d
OB
5094 }
5095 };
5096 if (my $err = $@) {
5097 $add_apply_error->($opt, $err);
055d554d 5098 } else {
98bc3aeb 5099 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
055d554d 5100 delete $conf->{$opt};
055d554d
DM
5101 }
5102 }
5103
3d48b95a 5104 PVE::QemuConfig->cleanup_pending($conf);
055d554d 5105
c930f99e
AD
5106 my $generate_cloudnit = undef;
5107
055d554d 5108 foreach my $opt (keys %{$conf->{pending}}) { # add/change
3d48b95a 5109 next if $opt eq 'delete'; # just to be sure
eb5e482d 5110 eval {
3d48b95a 5111 if (defined($conf->{$opt}) && is_valid_drivename($opt)) {
eb5e482d 5112 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
eb5e482d
OB
5113 }
5114 };
5115 if (my $err = $@) {
5116 $add_apply_error->($opt, $err);
055d554d 5117 } else {
c930f99e
AD
5118
5119 if (is_valid_drivename($opt)) {
5120 my $drive = parse_drive($opt, $conf->{pending}->{$opt});
5121 $generate_cloudnit = 1 if drive_is_cloudinit($drive);
5122 }
5123
eb5e482d 5124 $conf->{$opt} = delete $conf->{pending}->{$opt};
055d554d 5125 }
055d554d 5126 }
3d48b95a
OB
5127
5128 # write all changes at once to avoid unnecessary i/o
5129 PVE::QemuConfig->write_config($vmid, $conf);
c930f99e 5130 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid) if $generate_cloudnit;
055d554d
DM
5131}
5132
3eec5767 5133sub vmconfig_update_net {
d559309f 5134 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
3eec5767
DM
5135
5136 my $newnet = parse_net($value);
5137
5138 if ($conf->{$opt}) {
5139 my $oldnet = parse_net($conf->{$opt});
5140
0f1af9e7
OB
5141 if (safe_string_ne($oldnet->{model}, $newnet->{model}) ||
5142 safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
5143 safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
3eec5767
DM
5144 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
5145
5146 # for non online change, we try to hot-unplug
7196b757 5147 die "skip\n" if !$hotplug;
3eec5767
DM
5148 vm_deviceunplug($vmid, $conf, $opt);
5149 } else {
5150
5151 die "internal error" if $opt !~ m/net(\d+)/;
5152 my $iface = "tap${vmid}i$1";
a1b7d579 5153
0f1af9e7
OB
5154 if (safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
5155 safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
5156 safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
5157 safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
3eec5767 5158 PVE::Network::tap_unplug($iface);
28e129cc
AD
5159
5160 if ($have_sdn) {
5161 PVE::Network::SDN::Zones::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5162 } else {
5163 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5164 }
0f1af9e7 5165 } elsif (safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4f4fbeb0
WB
5166 # Rate can be applied on its own but any change above needs to
5167 # include the rate in tap_plug since OVS resets everything.
5168 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
3eec5767 5169 }
38c590d9 5170
0f1af9e7 5171 if (safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
25088687
DM
5172 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5173 }
5174
38c590d9 5175 return 1;
3eec5767
DM
5176 }
5177 }
a1b7d579 5178
7196b757 5179 if ($hotplug) {
d559309f 5180 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
38c590d9
DM
5181 } else {
5182 die "skip\n";
5183 }
3eec5767
DM
5184}
5185
74ea2c65
AD
5186sub vmconfig_update_agent {
5187 my ($conf, $opt, $value) = @_;
5188
5189 die "skip\n" if !$conf->{$opt};
5190
5191 my $hotplug_options = { fstrim_cloned_disks => 1 };
5192
5193 my $old_agent = parse_guest_agent($conf);
5194 my $agent = parse_guest_agent({$opt => $value});
5195
33f8b887 5196 for my $option (keys %$agent) { # added/changed options
74ea2c65
AD
5197 next if defined($hotplug_options->{$option});
5198 die "skip\n" if safe_string_ne($agent->{$option}, $old_agent->{$option});
5199 }
5200
33f8b887 5201 for my $option (keys %$old_agent) { # removed options
74ea2c65
AD
5202 next if defined($hotplug_options->{$option});
5203 die "skip\n" if safe_string_ne($old_agent->{$option}, $agent->{$option});
5204 }
33f8b887
TL
5205
5206 return; # either no actual change (e.g., format string reordered) or just hotpluggable changes
74ea2c65
AD
5207}
5208
a05cff86 5209sub vmconfig_update_disk {
9e7bce2c 5210 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
a05cff86
DM
5211
5212 my $drive = parse_drive($opt, $value);
5213
4df98f2f
TL
5214 if ($conf->{$opt} && (my $old_drive = parse_drive($opt, $conf->{$opt}))) {
5215 my $media = $drive->{media} || 'disk';
5216 my $oldmedia = $old_drive->{media} || 'disk';
5217 die "unable to change media type\n" if $media ne $oldmedia;
a05cff86 5218
4df98f2f 5219 if (!drive_is_cdrom($old_drive)) {
a05cff86 5220
4df98f2f 5221 if ($drive->{file} ne $old_drive->{file}) {
a05cff86 5222
4df98f2f 5223 die "skip\n" if !$hotplug;
a05cff86 5224
4df98f2f
TL
5225 # unplug and register as unused
5226 vm_deviceunplug($vmid, $conf, $opt);
5227 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
a1b7d579 5228
4df98f2f
TL
5229 } else {
5230 # update existing disk
5231
5232 # skip non hotpluggable value
5233 if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
5234 safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
5235 safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
5236 safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
5237 safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
5238 die "skip\n";
5239 }
a05cff86 5240
4df98f2f
TL
5241 # apply throttle
5242 if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5243 safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5244 safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5245 safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5246 safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5247 safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5248 safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5249 safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5250 safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5251 safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5252 safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
5253 safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5254 safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5255 safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5256 safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5257 safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5258 safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5259 safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
5260
5261 qemu_block_set_io_throttle(
5262 $vmid,"drive-$opt",
5263 ($drive->{mbps} || 0)*1024*1024,
5264 ($drive->{mbps_rd} || 0)*1024*1024,
5265 ($drive->{mbps_wr} || 0)*1024*1024,
5266 $drive->{iops} || 0,
5267 $drive->{iops_rd} || 0,
5268 $drive->{iops_wr} || 0,
5269 ($drive->{mbps_max} || 0)*1024*1024,
5270 ($drive->{mbps_rd_max} || 0)*1024*1024,
5271 ($drive->{mbps_wr_max} || 0)*1024*1024,
5272 $drive->{iops_max} || 0,
5273 $drive->{iops_rd_max} || 0,
5274 $drive->{iops_wr_max} || 0,
5275 $drive->{bps_max_length} || 1,
5276 $drive->{bps_rd_max_length} || 1,
5277 $drive->{bps_wr_max_length} || 1,
5278 $drive->{iops_max_length} || 1,
5279 $drive->{iops_rd_max_length} || 1,
5280 $drive->{iops_wr_max_length} || 1,
5281 );
a05cff86 5282
4df98f2f 5283 }
a1b7d579 5284
4df98f2f
TL
5285 return 1;
5286 }
4de1bb25 5287
4df98f2f 5288 } else { # cdrom
a1b7d579 5289
4df98f2f
TL
5290 if ($drive->{file} eq 'none') {
5291 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
5292 if (drive_is_cloudinit($old_drive)) {
5293 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5294 }
5295 } else {
5296 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
ce9fce79 5297
4df98f2f
TL
5298 # force eject if locked
5299 mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
ce9fce79 5300
4df98f2f
TL
5301 if ($path) {
5302 mon_cmd($vmid, "blockdev-change-medium",
5303 id => "$opt", filename => "$path");
4de1bb25 5304 }
a05cff86 5305 }
4df98f2f
TL
5306
5307 return 1;
a05cff86
DM
5308 }
5309 }
5310
a1b7d579 5311 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4de1bb25 5312 # hotplug new disks
f7b4356f 5313 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
d559309f 5314 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
a05cff86
DM
5315}
5316
9687287b
AD
5317sub vmconfig_update_cloudinit_drive {
5318 my ($storecfg, $conf, $vmid) = @_;
5319
5320 my $cloudinit_ds = undef;
5321 my $cloudinit_drive = undef;
5322
5323 PVE::QemuConfig->foreach_volume($conf, sub {
5324 my ($ds, $drive) = @_;
5325 if (PVE::QemuServer::drive_is_cloudinit($drive)) {
5326 $cloudinit_ds = $ds;
5327 $cloudinit_drive = $drive;
5328 }
5329 });
5330
5331 return if !$cloudinit_drive;
5332
5333 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5334 my $running = PVE::QemuServer::check_running($vmid);
5335
5336 if ($running) {
5337 my $path = PVE::Storage::path($storecfg, $cloudinit_drive->{file});
5338 if ($path) {
5339 mon_cmd($vmid, "eject", force => JSON::true, id => "$cloudinit_ds");
5340 mon_cmd($vmid, "blockdev-change-medium", id => "$cloudinit_ds", filename => "$path");
5341 }
5342 }
5343}
5344
13cfe3b7 5345# called in locked context by incoming migration
ba5396b5
FG
5346sub vm_migrate_get_nbd_disks {
5347 my ($storecfg, $conf, $replicated_volumes) = @_;
13cfe3b7
FG
5348
5349 my $local_volumes = {};
912792e2 5350 PVE::QemuConfig->foreach_volume($conf, sub {
13cfe3b7
FG
5351 my ($ds, $drive) = @_;
5352
5353 return if drive_is_cdrom($drive);
41c8671e 5354 return if $ds eq 'tpmstate0';
13cfe3b7
FG
5355
5356 my $volid = $drive->{file};
5357
5358 return if !$volid;
5359
5360 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5361
5362 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5363 return if $scfg->{shared};
ba5396b5
FG
5364
5365 # replicated disks re-use existing state via bitmap
5366 my $use_existing = $replicated_volumes->{$volid} ? 1 : 0;
5367 $local_volumes->{$ds} = [$volid, $storeid, $volname, $drive, $use_existing];
13cfe3b7 5368 });
ba5396b5
FG
5369 return $local_volumes;
5370}
5371
5372# called in locked context by incoming migration
5373sub vm_migrate_alloc_nbd_disks {
5374 my ($storecfg, $vmid, $source_volumes, $storagemap) = @_;
13cfe3b7 5375
13cfe3b7 5376 my $nbd = {};
ba5396b5 5377 foreach my $opt (sort keys %$source_volumes) {
5668463b 5378 my ($volid, $storeid, $volname, $drive, $use_existing, $format) = @{$source_volumes->{$opt}};
ba5396b5
FG
5379
5380 if ($use_existing) {
5381 $nbd->{$opt}->{drivestr} = print_drive($drive);
5382 $nbd->{$opt}->{volid} = $volid;
5383 $nbd->{$opt}->{replicated} = 1;
13cfe3b7
FG
5384 next;
5385 }
13cfe3b7 5386
5668463b
FG
5387 # storage mapping + volname = regular migration
5388 # storage mapping + format = remote migration
5389 # order of precedence, filtered by whether storage supports it:
5390 # 1. explicit requested format
5391 # 2. format of current volume
5392 # 3. default format of storage
bf8fc5a3 5393 if (!$storagemap->{identity}) {
82a03671 5394 $storeid = PVE::JSONSchema::map_id($storagemap, $storeid);
13cfe3b7 5395 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5668463b
FG
5396 if (!$format || !grep { $format eq $_ } @$validFormats) {
5397 if ($volname) {
5398 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5399 my $fileFormat = qemu_img_format($scfg, $volname);
5400 $format = $fileFormat
5401 if grep { $fileFormat eq $_ } @$validFormats;
5402 }
5403 $format //= $defFormat;
5404 }
13cfe3b7 5405 } else {
5668463b 5406 # can't happen for remote migration, so $volname is always defined
13cfe3b7
FG
5407 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5408 $format = qemu_img_format($scfg, $volname);
5409 }
5410
4df98f2f
TL
5411 my $size = $drive->{size} / 1024;
5412 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, $size);
13cfe3b7
FG
5413 my $newdrive = $drive;
5414 $newdrive->{format} = $format;
5415 $newdrive->{file} = $newvolid;
5416 my $drivestr = print_drive($newdrive);
ba5396b5
FG
5417 $nbd->{$opt}->{drivestr} = $drivestr;
5418 $nbd->{$opt}->{volid} = $newvolid;
13cfe3b7
FG
5419 }
5420
5421 return $nbd;
5422}
5423
5424# see vm_start_nolock for parameters, additionally:
5425# migrate_opts:
bf8fc5a3 5426# storagemap = parsed storage map for allocating NBD disks
3898a563
FG
5427sub vm_start {
5428 my ($storecfg, $vmid, $params, $migrate_opts) = @_;
5429
84da8217 5430 return PVE::QemuConfig->lock_config($vmid, sub {
3898a563
FG
5431 my $conf = PVE::QemuConfig->load_config($vmid, $migrate_opts->{migratedfrom});
5432
4ef13a7f
FG
5433 die "you can't start a vm if it's a template\n"
5434 if !$params->{skiptemplate} && PVE::QemuConfig->is_template($conf);
3898a563 5435
d544e0e0 5436 my $has_suspended_lock = PVE::QemuConfig->has_lock($conf, 'suspended');
8e0c97bb
SR
5437 my $has_backup_lock = PVE::QemuConfig->has_lock($conf, 'backup');
5438
5439 my $running = check_running($vmid, undef, $migrate_opts->{migratedfrom});
5440
5441 if ($has_backup_lock && $running) {
5442 # a backup is currently running, attempt to start the guest in the
5443 # existing QEMU instance
5444 return vm_resume($vmid);
5445 }
3898a563
FG
5446
5447 PVE::QemuConfig->check_lock($conf)
d544e0e0
FE
5448 if !($params->{skiplock} || $has_suspended_lock);
5449
5450 $params->{resume} = $has_suspended_lock || defined($conf->{vmstate});
3898a563 5451
8e0c97bb 5452 die "VM $vmid already running\n" if $running;
3898a563 5453
ba5396b5
FG
5454 if (my $storagemap = $migrate_opts->{storagemap}) {
5455 my $replicated = $migrate_opts->{replicated_volumes};
5456 my $disks = vm_migrate_get_nbd_disks($storecfg, $conf, $replicated);
5457 $migrate_opts->{nbd} = vm_migrate_alloc_nbd_disks($storecfg, $vmid, $disks, $storagemap);
5458
5459 foreach my $opt (keys %{$migrate_opts->{nbd}}) {
5460 $conf->{$opt} = $migrate_opts->{nbd}->{$opt}->{drivestr};
5461 }
5462 }
13cfe3b7 5463
84da8217 5464 return vm_start_nolock($storecfg, $vmid, $conf, $params, $migrate_opts);
3898a563
FG
5465 });
5466}
5467
5468
0c498cca
FG
5469# params:
5470# statefile => 'tcp', 'unix' for migration or path/volid for RAM state
5471# skiplock => 0/1, skip checking for config lock
4ef13a7f 5472# skiptemplate => 0/1, skip checking whether VM is template
0c498cca 5473# forcemachine => to force Qemu machine (rollback/migration)
58c64ad5 5474# forcecpu => a QEMU '-cpu' argument string to override get_cpu_options
0c498cca
FG
5475# timeout => in seconds
5476# paused => start VM in paused state (backup)
3898a563 5477# resume => resume from hibernation
5921764c
SR
5478# pbs-backing => {
5479# sata0 => {
5480# repository
5481# snapshot
5482# keyfile
5483# archive
5484# },
5485# virtio2 => ...
5486# }
0c498cca 5487# migrate_opts:
ba5396b5 5488# nbd => volumes for NBD exports (vm_migrate_alloc_nbd_disks)
0c498cca
FG
5489# migratedfrom => source node
5490# spice_ticket => used for spice migration, passed via tunnel/stdin
5491# network => CIDR of migration network
5492# type => secure/insecure - tunnel over encrypted connection or plain-text
0c498cca 5493# nbd_proto_version => int, 0 for TCP, 1 for UNIX
fd95d780 5494# replicated_volumes => which volids should be re-used with bitmaps for nbd migration
13d121d7
FE
5495# offline_volumes => new volids of offline migrated disks like tpmstate and cloudinit, not yet
5496# contained in config
3898a563
FG
5497sub vm_start_nolock {
5498 my ($storecfg, $vmid, $conf, $params, $migrate_opts) = @_;
1e3baf05 5499
3898a563
FG
5500 my $statefile = $params->{statefile};
5501 my $resume = $params->{resume};
3dcb98d5 5502
3898a563
FG
5503 my $migratedfrom = $migrate_opts->{migratedfrom};
5504 my $migration_type = $migrate_opts->{type};
7ceade4c 5505
84da8217
FG
5506 my $res = {};
5507
3898a563
FG
5508 # clean up leftover reboot request files
5509 eval { clear_reboot_request($vmid); };
5510 warn $@ if $@;
1e3baf05 5511
3898a563
FG
5512 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5513 vmconfig_apply_pending($vmid, $conf, $storecfg);
5514 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5515 }
64457ed4 5516
104f47a9
ML
5517 # don't regenerate the ISO if the VM is started as part of a live migration
5518 # this way we can reuse the old ISO with the correct config
5519 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid) if !$migratedfrom;
055d554d 5520
13d121d7
FE
5521 # override offline migrated volumes, conf is out of date still
5522 if (my $offline_volumes = $migrate_opts->{offline_volumes}) {
5523 for my $key (sort keys $offline_volumes->%*) {
5524 my $parsed = parse_drive($key, $conf->{$key});
5525 $parsed->{file} = $offline_volumes->{$key};
5526 $conf->{$key} = print_drive($parsed);
5527 }
fd95d780
FG
5528 }
5529
3898a563 5530 my $defaults = load_defaults();
0c9a7596 5531
3898a563
FG
5532 # set environment variable useful inside network script
5533 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
6c47d546 5534
3898a563 5535 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1);
9e784b11 5536
3898a563 5537 my $forcemachine = $params->{forcemachine};
ea1c2110 5538 my $forcecpu = $params->{forcecpu};
3898a563 5539 if ($resume) {
ea1c2110 5540 # enforce machine and CPU type on suspended vm to ensure HW compatibility
3898a563 5541 $forcemachine = $conf->{runningmachine};
ea1c2110 5542 $forcecpu = $conf->{runningcpu};
3898a563
FG
5543 print "Resuming suspended VM\n";
5544 }
7ceade4c 5545
5921764c
SR
5546 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid,
5547 $conf, $defaults, $forcemachine, $forcecpu, $params->{'pbs-backing'});
6c47d546 5548
3898a563
FG
5549 my $migration_ip;
5550 my $get_migration_ip = sub {
5551 my ($nodename) = @_;
b24e1ac2 5552
3898a563 5553 return $migration_ip if defined($migration_ip);
b24e1ac2 5554
3898a563 5555 my $cidr = $migrate_opts->{network};
0c498cca 5556
3898a563
FG
5557 if (!defined($cidr)) {
5558 my $dc_conf = PVE::Cluster::cfs_read_file('datacenter.cfg');
5559 $cidr = $dc_conf->{migration}->{network};
5560 }
b24e1ac2 5561
3898a563
FG
5562 if (defined($cidr)) {
5563 my $ips = PVE::Network::get_local_ip_from_cidr($cidr);
b24e1ac2 5564
3898a563
FG
5565 die "could not get IP: no address configured on local " .
5566 "node for network '$cidr'\n" if scalar(@$ips) == 0;
b24e1ac2 5567
3898a563
FG
5568 die "could not get IP: multiple addresses configured on local " .
5569 "node for network '$cidr'\n" if scalar(@$ips) > 1;
b24e1ac2 5570
3898a563
FG
5571 $migration_ip = @$ips[0];
5572 }
b24e1ac2 5573
3898a563
FG
5574 $migration_ip = PVE::Cluster::remote_node_ip($nodename, 1)
5575 if !defined($migration_ip);
b24e1ac2 5576
3898a563
FG
5577 return $migration_ip;
5578 };
b24e1ac2 5579
3898a563
FG
5580 my $migrate_uri;
5581 if ($statefile) {
5582 if ($statefile eq 'tcp') {
5583 my $localip = "localhost";
5584 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
5585 my $nodename = nodename();
2de2d6f7 5586
3898a563
FG
5587 if (!defined($migration_type)) {
5588 if (defined($datacenterconf->{migration}->{type})) {
5589 $migration_type = $datacenterconf->{migration}->{type};
5590 } else {
5591 $migration_type = 'secure';
b7a5a225 5592 }
3898a563 5593 }
b7a5a225 5594
3898a563
FG
5595 if ($migration_type eq 'insecure') {
5596 $localip = $get_migration_ip->($nodename);
5597 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5598 }
2de2d6f7 5599
3898a563
FG
5600 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5601 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5602 $migrate_uri = "tcp:${localip}:${migrate_port}";
5603 push @$cmd, '-incoming', $migrate_uri;
5604 push @$cmd, '-S';
1c9d54bf 5605
3898a563
FG
5606 } elsif ($statefile eq 'unix') {
5607 # should be default for secure migrations as a ssh TCP forward
5608 # tunnel is not deterministic reliable ready and fails regurarly
5609 # to set up in time, so use UNIX socket forwards
5610 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5611 unlink $socket_addr;
54323eed 5612
3898a563 5613 $migrate_uri = "unix:$socket_addr";
1c9d54bf 5614
3898a563
FG
5615 push @$cmd, '-incoming', $migrate_uri;
5616 push @$cmd, '-S';
1c9d54bf 5617
3898a563
FG
5618 } elsif (-e $statefile) {
5619 push @$cmd, '-loadstate', $statefile;
5620 } else {
5621 my $statepath = PVE::Storage::path($storecfg, $statefile);
5622 push @$vollist, $statefile;
5623 push @$cmd, '-loadstate', $statepath;
5624 }
5625 } elsif ($params->{paused}) {
5626 push @$cmd, '-S';
5627 }
5628
1fb1822e
DC
5629 my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
5630
5631 my $pci_devices = {}; # host pci devices
74c17b7a 5632 for (my $i = 0; $i < $PVE::QemuServer::PCI::MAX_HOSTPCI_DEVICES; $i++) {
1fb1822e
DC
5633 my $dev = $conf->{"hostpci$i"} or next;
5634 $pci_devices->{$i} = parse_hostpci($dev);
5635 }
5636
9c85548f
DC
5637 # do not reserve pciid for mediated devices, sysfs will error out for duplicate assignment
5638 my $real_pci_devices = [ grep { !(defined($_->{mdev}) && scalar($_->{pciid}->@*) == 1) } values $pci_devices->%* ];
5639
5640 # map to a flat list of pci ids
5641 my $pci_id_list = [ map { $_->{id} } map { $_->{pciid}->@* } $real_pci_devices->@* ];
5642
1fb1822e
DC
5643 # reserve all PCI IDs before actually doing anything with them
5644 PVE::QemuServer::PCI::reserve_pci_usage($pci_id_list, $vmid, $start_timeout);
5645
5646 eval {
bbf96e0f 5647 my $uuid;
1fb1822e
DC
5648 for my $id (sort keys %$pci_devices) {
5649 my $d = $pci_devices->{$id};
5650 for my $dev ($d->{pciid}->@*) {
bbf96e0f
DC
5651 my $info = PVE::QemuServer::PCI::prepare_pci_device($vmid, $dev->{id}, $id, $d->{mdev});
5652
5653 # nvidia grid needs the uuid of the mdev as qemu parameter
5654 if ($d->{mdev} && !defined($uuid) && $info->{vendor} eq '10de') {
5655 $uuid = PVE::QemuServer::PCI::generate_mdev_uuid($vmid, $id);
5656 }
1fb1822e
DC
5657 }
5658 }
bbf96e0f 5659 push @$cmd, '-uuid', $uuid if defined($uuid);
1fb1822e
DC
5660 };
5661 if (my $err = $@) {
1b189121 5662 eval { cleanup_pci_devices($vmid, $conf) };
1fb1822e
DC
5663 warn $@ if $@;
5664 die $err;
3898a563 5665 }
1e3baf05 5666
3898a563 5667 PVE::Storage::activate_volumes($storecfg, $vollist);
1e3baf05 5668
3898a563 5669 eval {
6bbcd71f 5670 run_command(['/bin/systemctl', 'stop', "$vmid.scope"], outfunc => sub{}, errfunc => sub{});
3898a563
FG
5671 };
5672 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5673 # timeout should be more than enough here...
39abafc8 5674 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 20);
3898a563 5675
6b7ef5e5 5676 my $cpuunits = PVE::CGroup::clamp_cpu_shares($conf->{cpuunits});
3898a563 5677
3898a563
FG
5678 my %run_params = (
5679 timeout => $statefile ? undef : $start_timeout,
5680 umask => 0077,
5681 noerr => 1,
5682 );
1e3baf05 5683
3898a563
FG
5684 # when migrating, prefix QEMU output so other side can pick up any
5685 # errors that might occur and show the user
5686 if ($migratedfrom) {
5687 $run_params{quiet} = 1;
5688 $run_params{logfunc} = sub { print "QEMU: $_[0]\n" };
5689 }
8bf30c2a 5690
212220a4 5691 my %systemd_properties = (
3898a563 5692 Slice => 'qemu.slice',
354e61aa
SR
5693 KillMode => 'process',
5694 SendSIGKILL => 0,
5695 TimeoutStopUSec => ULONG_MAX, # infinity
3898a563 5696 );
7023f3ea 5697
6cbd3eb8 5698 if (PVE::CGroup::cgroup_mode() == 2) {
212220a4 5699 $systemd_properties{CPUWeight} = $cpuunits;
6cbd3eb8 5700 } else {
212220a4 5701 $systemd_properties{CPUShares} = $cpuunits;
6cbd3eb8
AD
5702 }
5703
3898a563 5704 if (my $cpulimit = $conf->{cpulimit}) {
212220a4 5705 $systemd_properties{CPUQuota} = int($cpulimit * 100);
3898a563 5706 }
212220a4 5707 $systemd_properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
7023f3ea 5708
3898a563
FG
5709 my $run_qemu = sub {
5710 PVE::Tools::run_fork sub {
212220a4 5711 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %systemd_properties);
6e0216d8 5712
f9dde219
SR
5713 my $tpmpid;
5714 if (my $tpm = $conf->{tpmstate0}) {
5715 # start the TPM emulator so QEMU can connect on start
5716 $tpmpid = start_swtpm($storecfg, $vmid, $tpm, $migratedfrom);
5717 }
5718
3898a563 5719 my $exitcode = run_command($cmd, %run_params);
f9dde219 5720 if ($exitcode) {
23bee97d
FE
5721 if ($tpmpid) {
5722 warn "stopping swtpm instance (pid $tpmpid) due to QEMU startup error\n";
5723 kill 'TERM', $tpmpid;
5724 }
f9dde219
SR
5725 die "QEMU exited with code $exitcode\n";
5726 }
503308ed 5727 };
3898a563 5728 };
503308ed 5729
3898a563 5730 if ($conf->{hugepages}) {
7023f3ea 5731
3898a563
FG
5732 my $code = sub {
5733 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5734 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
7023f3ea 5735
3898a563
FG
5736 PVE::QemuServer::Memory::hugepages_mount();
5737 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
7023f3ea 5738
503308ed 5739 eval { $run_qemu->() };
3898a563 5740 if (my $err = $@) {
f36e9894
SR
5741 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology)
5742 if !$conf->{keephugepages};
3898a563
FG
5743 die $err;
5744 }
77cde36b 5745
f36e9894
SR
5746 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology)
5747 if !$conf->{keephugepages};
3898a563
FG
5748 };
5749 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
1e3baf05 5750
3898a563
FG
5751 } else {
5752 eval { $run_qemu->() };
5753 }
afdb31d5 5754
3898a563
FG
5755 if (my $err = $@) {
5756 # deactivate volumes if start fails
5757 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
1b189121
DC
5758 warn $@ if $@;
5759 eval { cleanup_pci_devices($vmid, $conf) };
5760 warn $@ if $@;
1fb1822e 5761
3898a563
FG
5762 die "start failed: $err";
5763 }
62de2cbd 5764
1fb1822e
DC
5765 # re-reserve all PCI IDs now that we can know the actual VM PID
5766 my $pid = PVE::QemuServer::Helpers::vm_running_locally($vmid);
5767 eval { PVE::QemuServer::PCI::reserve_pci_usage($pci_id_list, $vmid, undef, $pid) };
5768 warn $@ if $@;
5769
3898a563 5770 print "migration listens on $migrate_uri\n" if $migrate_uri;
84da8217 5771 $res->{migrate_uri} = $migrate_uri;
eb8cddb5 5772
3898a563
FG
5773 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
5774 eval { mon_cmd($vmid, "cont"); };
5775 warn $@ if $@;
5776 }
2189246c 5777
3898a563 5778 #start nbd server for storage migration
13cfe3b7 5779 if (my $nbd = $migrate_opts->{nbd}) {
3898a563 5780 my $nbd_protocol_version = $migrate_opts->{nbd_proto_version} // 0;
2189246c 5781
3898a563
FG
5782 my $migrate_storage_uri;
5783 # nbd_protocol_version > 0 for unix socket support
5784 if ($nbd_protocol_version > 0 && $migration_type eq 'secure') {
5785 my $socket_path = "/run/qemu-server/$vmid\_nbd.migrate";
5786 mon_cmd($vmid, "nbd-server-start", addr => { type => 'unix', data => { path => $socket_path } } );
5787 $migrate_storage_uri = "nbd:unix:$socket_path";
5788 } else {
5789 my $nodename = nodename();
5790 my $localip = $get_migration_ip->($nodename);
5791 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5792 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
5793
4df98f2f
TL
5794 mon_cmd($vmid, "nbd-server-start", addr => {
5795 type => 'inet',
5796 data => {
5797 host => "${localip}",
5798 port => "${storage_migrate_port}",
5799 },
5800 });
3898a563
FG
5801 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5802 $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
2189246c
AD
5803 }
5804
84da8217
FG
5805 $res->{migrate_storage_uri} = $migrate_storage_uri;
5806
13cfe3b7 5807 foreach my $opt (sort keys %$nbd) {
ba5396b5
FG
5808 my $drivestr = $nbd->{$opt}->{drivestr};
5809 my $volid = $nbd->{$opt}->{volid};
3898a563 5810 mon_cmd($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
84da8217
FG
5811 my $nbd_uri = "$migrate_storage_uri:exportname=drive-$opt";
5812 print "storage migration listens on $nbd_uri volume:$drivestr\n";
ba5396b5
FG
5813 print "re-using replicated volume: $opt - $volid\n"
5814 if $nbd->{$opt}->{replicated};
84da8217
FG
5815
5816 $res->{drives}->{$opt} = $nbd->{$opt};
5817 $res->{drives}->{$opt}->{nbd_uri} = $nbd_uri;
3898a563
FG
5818 }
5819 }
a89fded1 5820
3898a563
FG
5821 if ($migratedfrom) {
5822 eval {
5823 set_migration_caps($vmid);
5824 };
5825 warn $@ if $@;
5826
5827 if ($spice_port) {
5828 print "spice listens on port $spice_port\n";
84da8217 5829 $res->{spice_port} = $spice_port;
3898a563 5830 if ($migrate_opts->{spice_ticket}) {
4df98f2f
TL
5831 mon_cmd($vmid, "set_password", protocol => 'spice', password =>
5832 $migrate_opts->{spice_ticket});
3898a563 5833 mon_cmd($vmid, "expire_password", protocol => 'spice', time => "+30");
95a4b4a9 5834 }
3898a563 5835 }
95a4b4a9 5836
3898a563
FG
5837 } else {
5838 mon_cmd($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5839 if !$statefile && $conf->{balloon};
25088687 5840
3898a563
FG
5841 foreach my $opt (keys %$conf) {
5842 next if $opt !~ m/^net\d+$/;
5843 my $nicconf = parse_net($conf->{$opt});
5844 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
e18b0b99 5845 }
3898a563 5846 }
a1b7d579 5847
3898a563
FG
5848 mon_cmd($vmid, 'qom-set',
5849 path => "machine/peripheral/balloon0",
5850 property => "guest-stats-polling-interval",
5851 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
eb065317 5852
3898a563
FG
5853 if ($resume) {
5854 print "Resumed VM, removing state\n";
5855 if (my $vmstate = $conf->{vmstate}) {
5856 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5857 PVE::Storage::vdisk_free($storecfg, $vmstate);
7ceade4c 5858 }
ea1c2110 5859 delete $conf->@{qw(lock vmstate runningmachine runningcpu)};
3898a563
FG
5860 PVE::QemuConfig->write_config($vmid, $conf);
5861 }
7ceade4c 5862
3898a563 5863 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start');
84da8217
FG
5864
5865 return $res;
1e3baf05
DM
5866}
5867
1e3baf05 5868sub vm_commandline {
b14477e7 5869 my ($storecfg, $vmid, $snapname) = @_;
1e3baf05 5870
ffda963f 5871 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5872
e8a26810 5873 my ($forcemachine, $forcecpu);
b14477e7
RV
5874 if ($snapname) {
5875 my $snapshot = $conf->{snapshots}->{$snapname};
87d92707
TL
5876 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5877
ea1c2110
SR
5878 # check for machine or CPU overrides in snapshot
5879 $forcemachine = $snapshot->{runningmachine};
5880 $forcecpu = $snapshot->{runningcpu};
092868c4 5881
87d92707 5882 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
b14477e7 5883
b14477e7
RV
5884 $conf = $snapshot;
5885 }
5886
1e3baf05
DM
5887 my $defaults = load_defaults();
5888
e8a26810 5889 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu);
1e3baf05 5890
5930c1ff 5891 return PVE::Tools::cmd2string($cmd);
1e3baf05
DM
5892}
5893
5894sub vm_reset {
5895 my ($vmid, $skiplock) = @_;
5896
ffda963f 5897 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5898
ffda963f 5899 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5900
ffda963f 5901 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 5902
0a13e08e 5903 mon_cmd($vmid, "system_reset");
ff1a2432
DM
5904 });
5905}
5906
5907sub get_vm_volumes {
5908 my ($conf) = @_;
1e3baf05 5909
ff1a2432 5910 my $vollist = [];
d5769dc2 5911 foreach_volid($conf, sub {
392f8b5d 5912 my ($volid, $attr) = @_;
ff1a2432 5913
d5769dc2 5914 return if $volid =~ m|^/|;
ff1a2432 5915
d5769dc2
DM
5916 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5917 return if !$sid;
ff1a2432
DM
5918
5919 push @$vollist, $volid;
1e3baf05 5920 });
ff1a2432
DM
5921
5922 return $vollist;
5923}
5924
1b189121
DC
5925sub cleanup_pci_devices {
5926 my ($vmid, $conf) = @_;
5927
5928 foreach my $key (keys %$conf) {
5929 next if $key !~ m/^hostpci(\d+)$/;
5930 my $hostpciindex = $1;
5931 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $hostpciindex);
5932 my $d = parse_hostpci($conf->{$key});
faf72d6c
TL
5933 if ($d->{mdev}) {
5934 # NOTE: avoid PVE::SysFSTools::pci_cleanup_mdev_device as it requires PCI ID and we
5935 # don't want to break ABI just for this two liner
5936 my $dev_sysfs_dir = "/sys/bus/mdev/devices/$uuid";
5937 PVE::SysFSTools::file_write("$dev_sysfs_dir/remove", "1") if -e $dev_sysfs_dir;
5938 }
1b189121
DC
5939 }
5940 PVE::QemuServer::PCI::remove_pci_reservation($vmid);
5941}
5942
ff1a2432 5943sub vm_stop_cleanup {
70b04821 5944 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
ff1a2432 5945
745fed70 5946 eval {
ff1a2432 5947
254575e9
DM
5948 if (!$keepActive) {
5949 my $vollist = get_vm_volumes($conf);
5950 PVE::Storage::deactivate_volumes($storecfg, $vollist);
f9dde219
SR
5951
5952 if (my $tpmdrive = $conf->{tpmstate0}) {
5953 my $tpm = parse_drive("tpmstate0", $tpmdrive);
5954 my ($storeid, $volname) = PVE::Storage::parse_volume_id($tpm->{file}, 1);
5955 if ($storeid) {
5956 PVE::Storage::unmap_volume($storecfg, $tpm->{file});
5957 }
5958 }
254575e9 5959 }
a1b7d579 5960
ab6a046f 5961 foreach my $ext (qw(mon qmp pid vnc qga)) {
961bfcb2
DM
5962 unlink "/var/run/qemu-server/${vmid}.$ext";
5963 }
a1b7d579 5964
6dbcb073 5965 if ($conf->{ivshmem}) {
4df98f2f 5966 my $ivshmem = parse_property_string($ivshmem_fmt, $conf->{ivshmem});
4c5a6a24
TL
5967 # just delete it for now, VMs which have this already open do not
5968 # are affected, but new VMs will get a separated one. If this
5969 # becomes an issue we either add some sort of ref-counting or just
5970 # add a "don't delete on stop" flag to the ivshmem format.
6dbcb073
DC
5971 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name} // $vmid);
5972 }
5973
1b189121 5974 cleanup_pci_devices($vmid, $conf);
6ab45bd7 5975
70b04821 5976 vmconfig_apply_pending($vmid, $conf, $storecfg) if $apply_pending_changes;
745fed70
DM
5977 };
5978 warn $@ if $@; # avoid errors - just warn
1e3baf05
DM
5979}
5980
575d19da
DC
5981# call only in locked context
5982sub _do_vm_stop {
5983 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
9269013a 5984
575d19da
DC
5985 my $pid = check_running($vmid, $nocheck);
5986 return if !$pid;
1e3baf05 5987
575d19da
DC
5988 my $conf;
5989 if (!$nocheck) {
5990 $conf = PVE::QemuConfig->load_config($vmid);
5991 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5992 if (!defined($timeout) && $shutdown && $conf->{startup}) {
5993 my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
5994 $timeout = $opts->{down} if $opts->{down};
e6c3b671 5995 }
575d19da
DC
5996 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-stop');
5997 }
19672434 5998
575d19da
DC
5999 eval {
6000 if ($shutdown) {
a2af1bbe 6001 if (defined($conf) && get_qga_key($conf, 'enabled')) {
0a13e08e 6002 mon_cmd($vmid, "guest-shutdown", timeout => $timeout);
9269013a 6003 } else {
0a13e08e 6004 mon_cmd($vmid, "system_powerdown");
1e3baf05
DM
6005 }
6006 } else {
0a13e08e 6007 mon_cmd($vmid, "quit");
1e3baf05 6008 }
575d19da
DC
6009 };
6010 my $err = $@;
1e3baf05 6011
575d19da
DC
6012 if (!$err) {
6013 $timeout = 60 if !defined($timeout);
1e3baf05
DM
6014
6015 my $count = 0;
e6c3b671 6016 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
6017 $count++;
6018 sleep 1;
6019 }
6020
6021 if ($count >= $timeout) {
575d19da
DC
6022 if ($force) {
6023 warn "VM still running - terminating now with SIGTERM\n";
6024 kill 15, $pid;
6025 } else {
6026 die "VM quit/powerdown failed - got timeout\n";
6027 }
6028 } else {
6029 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
6030 return;
1e3baf05 6031 }
575d19da 6032 } else {
d60cbb97
TL
6033 if (!check_running($vmid, $nocheck)) {
6034 warn "Unexpected: VM shutdown command failed, but VM not running anymore..\n";
6035 return;
6036 }
6037 if ($force) {
575d19da
DC
6038 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
6039 kill 15, $pid;
6040 } else {
6041 die "VM quit/powerdown failed\n";
6042 }
6043 }
6044
6045 # wait again
6046 $timeout = 10;
6047
6048 my $count = 0;
6049 while (($count < $timeout) && check_running($vmid, $nocheck)) {
6050 $count++;
6051 sleep 1;
6052 }
6053
6054 if ($count >= $timeout) {
6055 warn "VM still running - terminating now with SIGKILL\n";
6056 kill 9, $pid;
6057 sleep 1;
6058 }
1e3baf05 6059
575d19da
DC
6060 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
6061}
6062
6063# Note: use $nocheck to skip tests if VM configuration file exists.
6064# We need that when migration VMs to other nodes (files already moved)
6065# Note: we set $keepActive in vzdump stop mode - volumes need to stay active
6066sub vm_stop {
6067 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
6068
6069 $force = 1 if !defined($force) && !$shutdown;
6070
6071 if ($migratedfrom){
6072 my $pid = check_running($vmid, $nocheck, $migratedfrom);
6073 kill 15, $pid if $pid;
6074 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
6075 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 0);
6076 return;
6077 }
6078
6079 PVE::QemuConfig->lock_config($vmid, sub {
6080 _do_vm_stop($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
ff1a2432 6081 });
1e3baf05
DM
6082}
6083
165411f0
DC
6084sub vm_reboot {
6085 my ($vmid, $timeout) = @_;
6086
6087 PVE::QemuConfig->lock_config($vmid, sub {
66026117 6088 eval {
165411f0 6089
66026117
OB
6090 # only reboot if running, as qmeventd starts it again on a stop event
6091 return if !check_running($vmid);
165411f0 6092
66026117 6093 create_reboot_request($vmid);
165411f0 6094
66026117
OB
6095 my $storecfg = PVE::Storage::config();
6096 _do_vm_stop($storecfg, $vmid, undef, undef, $timeout, 1);
165411f0 6097
66026117
OB
6098 };
6099 if (my $err = $@) {
3c1c3fe6 6100 # avoid that the next normal shutdown will be confused for a reboot
66026117
OB
6101 clear_reboot_request($vmid);
6102 die $err;
6103 }
165411f0
DC
6104 });
6105}
6106
75c24bba 6107# note: if using the statestorage parameter, the caller has to check privileges
1e3baf05 6108sub vm_suspend {
48b4cdc2 6109 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
159719e5
DC
6110
6111 my $conf;
6112 my $path;
6113 my $storecfg;
6114 my $vmstate;
1e3baf05 6115
ffda963f 6116 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 6117
159719e5 6118 $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 6119
159719e5 6120 my $is_backing_up = PVE::QemuConfig->has_lock($conf, 'backup');
e79706d4 6121 PVE::QemuConfig->check_lock($conf)
159719e5
DC
6122 if !($skiplock || $is_backing_up);
6123
6124 die "cannot suspend to disk during backup\n"
6125 if $is_backing_up && $includestate;
bcb7c9cf 6126
159719e5
DC
6127 if ($includestate) {
6128 $conf->{lock} = 'suspending';
6129 my $date = strftime("%Y-%m-%d", localtime(time()));
6130 $storecfg = PVE::Storage::config();
75c24bba
DC
6131 if (!$statestorage) {
6132 $statestorage = find_vmstate_storage($conf, $storecfg);
6133 # check permissions for the storage
6134 my $rpcenv = PVE::RPCEnvironment::get();
6135 if ($rpcenv->{type} ne 'cli') {
6136 my $authuser = $rpcenv->get_user();
6137 $rpcenv->check($authuser, "/storage/$statestorage", ['Datastore.AllocateSpace']);
6138 }
6139 }
6140
6141
4df98f2f
TL
6142 $vmstate = PVE::QemuConfig->__snapshot_save_vmstate(
6143 $vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
159719e5
DC
6144 $path = PVE::Storage::path($storecfg, $vmstate);
6145 PVE::QemuConfig->write_config($vmid, $conf);
6146 } else {
0a13e08e 6147 mon_cmd($vmid, "stop");
159719e5 6148 }
1e3baf05 6149 });
159719e5
DC
6150
6151 if ($includestate) {
6152 # save vm state
6153 PVE::Storage::activate_volumes($storecfg, [$vmstate]);
6154
6155 eval {
27a5be53 6156 set_migration_caps($vmid, 1);
0a13e08e 6157 mon_cmd($vmid, "savevm-start", statefile => $path);
159719e5 6158 for(;;) {
0a13e08e 6159 my $state = mon_cmd($vmid, "query-savevm");
159719e5
DC
6160 if (!$state->{status}) {
6161 die "savevm not active\n";
6162 } elsif ($state->{status} eq 'active') {
6163 sleep(1);
6164 next;
6165 } elsif ($state->{status} eq 'completed') {
b0a9a385 6166 print "State saved, quitting\n";
159719e5
DC
6167 last;
6168 } elsif ($state->{status} eq 'failed' && $state->{error}) {
6169 die "query-savevm failed with error '$state->{error}'\n"
6170 } else {
6171 die "query-savevm returned status '$state->{status}'\n";
6172 }
6173 }
6174 };
6175 my $err = $@;
6176
6177 PVE::QemuConfig->lock_config($vmid, sub {
6178 $conf = PVE::QemuConfig->load_config($vmid);
6179 if ($err) {
6180 # cleanup, but leave suspending lock, to indicate something went wrong
6181 eval {
0a13e08e 6182 mon_cmd($vmid, "savevm-end");
159719e5
DC
6183 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
6184 PVE::Storage::vdisk_free($storecfg, $vmstate);
ea1c2110 6185 delete $conf->@{qw(vmstate runningmachine runningcpu)};
159719e5
DC
6186 PVE::QemuConfig->write_config($vmid, $conf);
6187 };
6188 warn $@ if $@;
6189 die $err;
6190 }
6191
6192 die "lock changed unexpectedly\n"
6193 if !PVE::QemuConfig->has_lock($conf, 'suspending');
6194
0a13e08e 6195 mon_cmd($vmid, "quit");
159719e5
DC
6196 $conf->{lock} = 'suspended';
6197 PVE::QemuConfig->write_config($vmid, $conf);
6198 });
6199 }
1e3baf05
DM
6200}
6201
6202sub vm_resume {
289e0b85 6203 my ($vmid, $skiplock, $nocheck) = @_;
1e3baf05 6204
ffda963f 6205 PVE::QemuConfig->lock_config($vmid, sub {
0a13e08e 6206 my $res = mon_cmd($vmid, 'query-status');
c2786bed 6207 my $resume_cmd = 'cont';
8e0c97bb 6208 my $reset = 0;
c2786bed 6209
8e0c97bb
SR
6210 if ($res->{status}) {
6211 return if $res->{status} eq 'running'; # job done, go home
6212 $resume_cmd = 'system_wakeup' if $res->{status} eq 'suspended';
6213 $reset = 1 if $res->{status} eq 'shutdown';
c2786bed
DC
6214 }
6215
289e0b85 6216 if (!$nocheck) {
1e3baf05 6217
ffda963f 6218 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 6219
e79706d4
FG
6220 PVE::QemuConfig->check_lock($conf)
6221 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
289e0b85 6222 }
3e24733b 6223
8e0c97bb
SR
6224 if ($reset) {
6225 # required if a VM shuts down during a backup and we get a resume
6226 # request before the backup finishes for example
6227 mon_cmd($vmid, "system_reset");
6228 }
0a13e08e 6229 mon_cmd($vmid, $resume_cmd);
1e3baf05
DM
6230 });
6231}
6232
5fdbe4f0
DM
6233sub vm_sendkey {
6234 my ($vmid, $skiplock, $key) = @_;
1e3baf05 6235
ffda963f 6236 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 6237
ffda963f 6238 my $conf = PVE::QemuConfig->load_config($vmid);
f5eb281a 6239
7b7c6d1b 6240 # there is no qmp command, so we use the human monitor command
0a13e08e 6241 my $res = PVE::QemuServer::Monitor::hmp_cmd($vmid, "sendkey $key");
d30820d6 6242 die $res if $res ne '';
1e3baf05
DM
6243 });
6244}
6245
3e16d5fc
DM
6246# vzdump restore implementaion
6247
ed221350 6248sub tar_archive_read_firstfile {
3e16d5fc 6249 my $archive = shift;
afdb31d5 6250
3e16d5fc
DM
6251 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
6252
6253 # try to detect archive type first
387ba257 6254 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
3e16d5fc 6255 die "unable to open file '$archive'\n";
387ba257 6256 my $firstfile = <$fh>;
3e16d5fc 6257 kill 15, $pid;
387ba257 6258 close $fh;
3e16d5fc
DM
6259
6260 die "ERROR: archive contaions no data\n" if !$firstfile;
6261 chomp $firstfile;
6262
6263 return $firstfile;
6264}
6265
ed221350
DM
6266sub tar_restore_cleanup {
6267 my ($storecfg, $statfile) = @_;
3e16d5fc
DM
6268
6269 print STDERR "starting cleanup\n";
6270
6271 if (my $fd = IO::File->new($statfile, "r")) {
6272 while (defined(my $line = <$fd>)) {
6273 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6274 my $volid = $2;
6275 eval {
6276 if ($volid =~ m|^/|) {
6277 unlink $volid || die 'unlink failed\n';
6278 } else {
ed221350 6279 PVE::Storage::vdisk_free($storecfg, $volid);
3e16d5fc 6280 }
afdb31d5 6281 print STDERR "temporary volume '$volid' sucessfuly removed\n";
3e16d5fc
DM
6282 };
6283 print STDERR "unable to cleanup '$volid' - $@" if $@;
6284 } else {
6285 print STDERR "unable to parse line in statfile - $line";
afdb31d5 6286 }
3e16d5fc
DM
6287 }
6288 $fd->close();
6289 }
6290}
6291
d1e92cf6 6292sub restore_file_archive {
a0d1b1a2 6293 my ($archive, $vmid, $user, $opts) = @_;
3e16d5fc 6294
a2ec5a67
FG
6295 return restore_vma_archive($archive, $vmid, $user, $opts)
6296 if $archive eq '-';
6297
c6d51783
AA
6298 my $info = PVE::Storage::archive_info($archive);
6299 my $format = $opts->{format} // $info->{format};
6300 my $comp = $info->{compression};
91bd6c90
DM
6301
6302 # try to detect archive format
6303 if ($format eq 'tar') {
6304 return restore_tar_archive($archive, $vmid, $user, $opts);
6305 } else {
6306 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
6307 }
6308}
6309
d1e92cf6
DM
6310# hepler to remove disks that will not be used after restore
6311my $restore_cleanup_oldconf = sub {
6312 my ($storecfg, $vmid, $oldconf, $virtdev_hash) = @_;
6313
01a4377f
FE
6314 my $kept_disks = {};
6315
912792e2 6316 PVE::QemuConfig->foreach_volume($oldconf, sub {
d1e92cf6
DM
6317 my ($ds, $drive) = @_;
6318
6319 return if drive_is_cdrom($drive, 1);
6320
6321 my $volid = $drive->{file};
6322 return if !$volid || $volid =~ m|^/|;
6323
6324 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
6325 return if !$path || !$owner || ($owner != $vmid);
6326
6327 # Note: only delete disk we want to restore
6328 # other volumes will become unused
6329 if ($virtdev_hash->{$ds}) {
6330 eval { PVE::Storage::vdisk_free($storecfg, $volid); };
6331 if (my $err = $@) {
6332 warn $err;
6333 }
01a4377f
FE
6334 } else {
6335 $kept_disks->{$volid} = 1;
d1e92cf6
DM
6336 }
6337 });
6338
01a4377f
FE
6339 # after the restore we have no snapshots anymore
6340 for my $snapname (keys $oldconf->{snapshots}->%*) {
d1e92cf6
DM
6341 my $snap = $oldconf->{snapshots}->{$snapname};
6342 if ($snap->{vmstate}) {
6343 eval { PVE::Storage::vdisk_free($storecfg, $snap->{vmstate}); };
6344 if (my $err = $@) {
6345 warn $err;
6346 }
6347 }
01a4377f
FE
6348
6349 for my $volid (keys $kept_disks->%*) {
6350 eval { PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snapname); };
6351 warn $@ if $@;
6352 }
d1e92cf6
DM
6353 }
6354};
6355
9f3d73bc
DM
6356# Helper to parse vzdump backup device hints
6357#
6358# $rpcenv: Environment, used to ckeck storage permissions
6359# $user: User ID, to check storage permissions
6360# $storecfg: Storage configuration
6361# $fh: the file handle for reading the configuration
6362# $devinfo: should contain device sizes for all backu-up'ed devices
6363# $options: backup options (pool, default storage)
6364#
6365# Return: $virtdev_hash, updates $devinfo (add devname, virtdev, format, storeid)
6366my $parse_backup_hints = sub {
6367 my ($rpcenv, $user, $storecfg, $fh, $devinfo, $options) = @_;
d1e92cf6 6368
36d4bdcb
TL
6369 my $check_storage = sub { # assert if an image can be allocate
6370 my ($storeid, $scfg) = @_;
6371 die "Content type 'images' is not available on storage '$storeid'\n"
6372 if !$scfg->{content}->{images};
6373 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace'])
6374 if $user ne 'root@pam';
6375 };
d1e92cf6 6376
36d4bdcb 6377 my $virtdev_hash = {};
9f3d73bc
DM
6378 while (defined(my $line = <$fh>)) {
6379 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6380 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6381 die "archive does not contain data for drive '$virtdev'\n"
6382 if !$devinfo->{$devname};
6383
6384 if (defined($options->{storage})) {
6385 $storeid = $options->{storage} || 'local';
6386 } elsif (!$storeid) {
6387 $storeid = 'local';
d1e92cf6 6388 }
9f3d73bc
DM
6389 $format = 'raw' if !$format;
6390 $devinfo->{$devname}->{devname} = $devname;
6391 $devinfo->{$devname}->{virtdev} = $virtdev;
6392 $devinfo->{$devname}->{format} = $format;
6393 $devinfo->{$devname}->{storeid} = $storeid;
6394
62af60cd 6395 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
36d4bdcb 6396 $check_storage->($storeid, $scfg); # permission and content type check
d1e92cf6 6397
9f3d73bc
DM
6398 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6399 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6400 my $virtdev = $1;
6401 my $drive = parse_drive($virtdev, $2);
36d4bdcb 6402
9f3d73bc
DM
6403 if (drive_is_cloudinit($drive)) {
6404 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
5364990d
TL
6405 $storeid = $options->{storage} if defined ($options->{storage});
6406 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
9f3d73bc 6407 my $format = qemu_img_format($scfg, $volname); # has 'raw' fallback
d1e92cf6 6408
36d4bdcb 6409 $check_storage->($storeid, $scfg); # permission and content type check
9f8ba326 6410
9f3d73bc
DM
6411 $virtdev_hash->{$virtdev} = {
6412 format => $format,
5364990d 6413 storeid => $storeid,
9f3d73bc
DM
6414 size => PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE,
6415 is_cloudinit => 1,
6416 };
d1e92cf6 6417 }
9f3d73bc
DM
6418 }
6419 }
d1e92cf6 6420
9f3d73bc
DM
6421 return $virtdev_hash;
6422};
d1e92cf6 6423
9f3d73bc
DM
6424# Helper to allocate and activate all volumes required for a restore
6425#
6426# $storecfg: Storage configuration
6427# $virtdev_hash: as returned by parse_backup_hints()
6428#
6429# Returns: { $virtdev => $volid }
6430my $restore_allocate_devices = sub {
6431 my ($storecfg, $virtdev_hash, $vmid) = @_;
d1e92cf6 6432
9f3d73bc
DM
6433 my $map = {};
6434 foreach my $virtdev (sort keys %$virtdev_hash) {
6435 my $d = $virtdev_hash->{$virtdev};
6436 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
6437 my $storeid = $d->{storeid};
6438 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
d1e92cf6 6439
9f3d73bc
DM
6440 # test if requested format is supported
6441 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
6442 my $supported = grep { $_ eq $d->{format} } @$validFormats;
6443 $d->{format} = $defFormat if !$supported;
d1e92cf6 6444
9f3d73bc
DM
6445 my $name;
6446 if ($d->{is_cloudinit}) {
6447 $name = "vm-$vmid-cloudinit";
c997e24a
ML
6448 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
6449 if ($scfg->{path}) {
6450 $name .= ".$d->{format}";
6451 }
d1e92cf6
DM
6452 }
6453
4df98f2f
TL
6454 my $volid = PVE::Storage::vdisk_alloc(
6455 $storecfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
d1e92cf6 6456
9f3d73bc
DM
6457 print STDERR "new volume ID is '$volid'\n";
6458 $d->{volid} = $volid;
d1e92cf6 6459
9f3d73bc 6460 PVE::Storage::activate_volumes($storecfg, [$volid]);
d1e92cf6 6461
9f3d73bc 6462 $map->{$virtdev} = $volid;
d1e92cf6
DM
6463 }
6464
9f3d73bc
DM
6465 return $map;
6466};
d1e92cf6 6467
c62d7cf5 6468sub restore_update_config_line {
eabac302 6469 my ($cookie, $map, $line, $unique) = @_;
91bd6c90 6470
98a4b3fb
FE
6471 return '' if $line =~ m/^\#qmdump\#/;
6472 return '' if $line =~ m/^\#vzdump\#/;
6473 return '' if $line =~ m/^lock:/;
6474 return '' if $line =~ m/^unused\d+:/;
6475 return '' if $line =~ m/^parent:/;
6476
6477 my $res = '';
91bd6c90 6478
b5b99790 6479 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
91bd6c90
DM
6480 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6481 # try to convert old 1.X settings
6482 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6483 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
6484 my ($model, $macaddr) = split(/\=/, $devconfig);
b5b99790 6485 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
91bd6c90
DM
6486 my $net = {
6487 model => $model,
6488 bridge => "vmbr$ind",
6489 macaddr => $macaddr,
6490 };
6491 my $netstr = print_net($net);
6492
98a4b3fb 6493 $res .= "net$cookie->{netcount}: $netstr\n";
91bd6c90
DM
6494 $cookie->{netcount}++;
6495 }
6496 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6497 my ($id, $netstr) = ($1, $2);
6498 my $net = parse_net($netstr);
b5b99790 6499 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
91bd6c90 6500 $netstr = print_net($net);
98a4b3fb 6501 $res .= "$id: $netstr\n";
f9dde219 6502 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk|tpmstate)\d+):\s*(\S+)\s*$/) {
91bd6c90 6503 my $virtdev = $1;
907ea891 6504 my $value = $3;
d9faf790
WB
6505 my $di = parse_drive($virtdev, $value);
6506 if (defined($di->{backup}) && !$di->{backup}) {
98a4b3fb 6507 $res .= "#$line";
c0f7406e 6508 } elsif ($map->{$virtdev}) {
8fd57431 6509 delete $di->{format}; # format can change on restore
91bd6c90 6510 $di->{file} = $map->{$virtdev};
71c58bb7 6511 $value = print_drive($di);
98a4b3fb 6512 $res .= "$virtdev: $value\n";
91bd6c90 6513 } else {
98a4b3fb 6514 $res .= $line;
91bd6c90 6515 }
1a0c2f03 6516 } elsif (($line =~ m/^vmgenid: (.*)/)) {
babecffe 6517 my $vmgenid = $1;
6ee499ff 6518 if ($vmgenid ne '0') {
1a0c2f03 6519 # always generate a new vmgenid if there was a valid one setup
6ee499ff
DC
6520 $vmgenid = generate_uuid();
6521 }
98a4b3fb 6522 $res .= "vmgenid: $vmgenid\n";
19a5dd55
WL
6523 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6524 my ($uuid, $uuid_str);
6525 UUID::generate($uuid);
6526 UUID::unparse($uuid, $uuid_str);
6527 my $smbios1 = parse_smbios1($2);
6528 $smbios1->{uuid} = $uuid_str;
98a4b3fb 6529 $res .= $1.print_smbios1($smbios1)."\n";
91bd6c90 6530 } else {
98a4b3fb 6531 $res .= $line;
91bd6c90 6532 }
98a4b3fb
FE
6533
6534 return $res;
c62d7cf5 6535}
9f3d73bc
DM
6536
6537my $restore_deactivate_volumes = sub {
e8b07b29 6538 my ($storecfg, $virtdev_hash) = @_;
9f3d73bc
DM
6539
6540 my $vollist = [];
e8b07b29
FE
6541 for my $dev (values $virtdev_hash->%*) {
6542 push $vollist->@*, $dev->{volid} if $dev->{volid};
9f3d73bc
DM
6543 }
6544
ff86112c
FE
6545 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
6546 print STDERR $@ if $@;
9f3d73bc
DM
6547};
6548
6549my $restore_destroy_volumes = sub {
e8b07b29 6550 my ($storecfg, $virtdev_hash) = @_;
9f3d73bc 6551
e8b07b29
FE
6552 for my $dev (values $virtdev_hash->%*) {
6553 my $volid = $dev->{volid} or next;
9f3d73bc 6554 eval {
e60afe82 6555 PVE::Storage::vdisk_free($storecfg, $volid);
9f3d73bc
DM
6556 print STDERR "temporary volume '$volid' sucessfuly removed\n";
6557 };
6558 print STDERR "unable to cleanup '$volid' - $@" if $@;
6559 }
6560};
91bd6c90 6561
202a2a0b
FE
6562my $restore_merge_config = sub {
6563 my ($filename, $backup_conf_raw, $override_conf) = @_;
6564
6565 my $backup_conf = parse_vm_config($filename, $backup_conf_raw);
6566 for my $key (keys $override_conf->%*) {
6567 $backup_conf->{$key} = $override_conf->{$key};
6568 }
6569
6570 return $backup_conf;
6571};
6572
91bd6c90 6573sub scan_volids {
9a8ba127 6574 my ($cfg, $vmid) = @_;
91bd6c90 6575
9a8ba127 6576 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid, undef, 'images');
91bd6c90
DM
6577
6578 my $volid_hash = {};
6579 foreach my $storeid (keys %$info) {
6580 foreach my $item (@{$info->{$storeid}}) {
6581 next if !($item->{volid} && $item->{size});
5996a936 6582 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
91bd6c90
DM
6583 $volid_hash->{$item->{volid}} = $item;
6584 }
6585 }
6586
6587 return $volid_hash;
6588}
6589
68b108ee 6590sub update_disk_config {
91bd6c90 6591 my ($vmid, $conf, $volid_hash) = @_;
be190583 6592
91bd6c90 6593 my $changes;
9b29cbd0 6594 my $prefix = "VM $vmid";
91bd6c90 6595
c449137a
DC
6596 # used and unused disks
6597 my $referenced = {};
91bd6c90 6598
5996a936
DM
6599 # Note: it is allowed to define multiple storages with same path (alias), so
6600 # we need to check both 'volid' and real 'path' (two different volid can point
6601 # to the same path).
6602
c449137a 6603 my $referencedpath = {};
be190583 6604
91bd6c90 6605 # update size info
0c4fef3f 6606 PVE::QemuConfig->foreach_volume($conf, sub {
ca04977c 6607 my ($opt, $drive) = @_;
91bd6c90 6608
ca04977c
FE
6609 my $volid = $drive->{file};
6610 return if !$volid;
4df98f2f 6611 my $volume = $volid_hash->{$volid};
91bd6c90 6612
ca04977c
FE
6613 # mark volid as "in-use" for next step
6614 $referenced->{$volid} = 1;
4df98f2f 6615 if ($volume && (my $path = $volume->{path})) {
ca04977c 6616 $referencedpath->{$path} = 1;
91bd6c90 6617 }
ca04977c
FE
6618
6619 return if drive_is_cdrom($drive);
4df98f2f 6620 return if !$volume;
ca04977c 6621
4df98f2f 6622 my ($updated, $msg) = PVE::QemuServer::Drive::update_disksize($drive, $volume->{size});
ca04977c
FE
6623 if (defined($updated)) {
6624 $changes = 1;
6625 $conf->{$opt} = print_drive($updated);
9b29cbd0 6626 print "$prefix ($opt): $msg\n";
ca04977c
FE
6627 }
6628 });
91bd6c90 6629
5996a936 6630 # remove 'unusedX' entry if volume is used
ca04977c
FE
6631 PVE::QemuConfig->foreach_unused_volume($conf, sub {
6632 my ($opt, $drive) = @_;
6633
6634 my $volid = $drive->{file};
6635 return if !$volid;
6636
f7d1505b
TL
6637 my $path;
6638 $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
c449137a 6639 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
68b108ee 6640 print "$prefix remove entry '$opt', its volume '$volid' is in use\n";
5996a936
DM
6641 $changes = 1;
6642 delete $conf->{$opt};
6643 }
c449137a
DC
6644
6645 $referenced->{$volid} = 1;
6646 $referencedpath->{$path} = 1 if $path;
ca04977c 6647 });
5996a936 6648
91bd6c90
DM
6649 foreach my $volid (sort keys %$volid_hash) {
6650 next if $volid =~ m/vm-$vmid-state-/;
c449137a 6651 next if $referenced->{$volid};
5996a936
DM
6652 my $path = $volid_hash->{$volid}->{path};
6653 next if !$path; # just to be sure
c449137a 6654 next if $referencedpath->{$path};
91bd6c90 6655 $changes = 1;
53b81297 6656 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
68b108ee 6657 print "$prefix add unreferenced volume '$volid' as '$key' to config\n";
c449137a 6658 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
91bd6c90
DM
6659 }
6660
6661 return $changes;
6662}
6663
6664sub rescan {
9224dcee 6665 my ($vmid, $nolock, $dryrun) = @_;
91bd6c90 6666
20519efc 6667 my $cfg = PVE::Storage::config();
91bd6c90 6668
53b81297 6669 print "rescan volumes...\n";
9a8ba127 6670 my $volid_hash = scan_volids($cfg, $vmid);
91bd6c90
DM
6671
6672 my $updatefn = sub {
6673 my ($vmid) = @_;
6674
ffda963f 6675 my $conf = PVE::QemuConfig->load_config($vmid);
be190583 6676
ffda963f 6677 PVE::QemuConfig->check_lock($conf);
91bd6c90 6678
03da3f0d
DM
6679 my $vm_volids = {};
6680 foreach my $volid (keys %$volid_hash) {
6681 my $info = $volid_hash->{$volid};
6682 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
6683 }
6684
68b108ee 6685 my $changes = update_disk_config($vmid, $conf, $vm_volids);
91bd6c90 6686
9224dcee 6687 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
91bd6c90
DM
6688 };
6689
6690 if (defined($vmid)) {
6691 if ($nolock) {
6692 &$updatefn($vmid);
6693 } else {
ffda963f 6694 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
91bd6c90
DM
6695 }
6696 } else {
6697 my $vmlist = config_list();
6698 foreach my $vmid (keys %$vmlist) {
6699 if ($nolock) {
6700 &$updatefn($vmid);
6701 } else {
ffda963f 6702 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
be190583 6703 }
91bd6c90
DM
6704 }
6705 }
6706}
6707
9f3d73bc
DM
6708sub restore_proxmox_backup_archive {
6709 my ($archive, $vmid, $user, $options) = @_;
6710
6711 my $storecfg = PVE::Storage::config();
6712
6713 my ($storeid, $volname) = PVE::Storage::parse_volume_id($archive);
6714 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
6715
9f3d73bc 6716 my $fingerprint = $scfg->{fingerprint};
503e96f8 6717 my $keyfile = PVE::Storage::PBSPlugin::pbs_encryption_key_file_name($storecfg, $storeid);
9f3d73bc 6718
fbec3f89 6719 my $repo = PVE::PBSClient::get_repository($scfg);
2dda626d 6720 my $namespace = $scfg->{namespace};
dea4b04c 6721
26731a3c 6722 # This is only used for `pbs-restore` and the QEMU PBS driver (live-restore)
9f3d73bc
DM
6723 my $password = PVE::Storage::PBSPlugin::pbs_get_password($scfg, $storeid);
6724 local $ENV{PBS_PASSWORD} = $password;
6725 local $ENV{PBS_FINGERPRINT} = $fingerprint if defined($fingerprint);
6726
6727 my ($vtype, $pbs_backup_name, undef, undef, undef, undef, $format) =
6728 PVE::Storage::parse_volname($storecfg, $archive);
6729
6730 die "got unexpected vtype '$vtype'\n" if $vtype ne 'backup';
6731
6732 die "got unexpected backup format '$format'\n" if $format ne 'pbs-vm';
6733
6734 my $tmpdir = "/var/tmp/vzdumptmp$$";
6735 rmtree $tmpdir;
6736 mkpath $tmpdir;
6737
6738 my $conffile = PVE::QemuConfig->config_file($vmid);
9f3d73bc
DM
6739 # disable interrupts (always do cleanups)
6740 local $SIG{INT} =
6741 local $SIG{TERM} =
6742 local $SIG{QUIT} =
6743 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
6744
6745 # Note: $oldconf is undef if VM does not exists
6746 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6747 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
98a4b3fb 6748 my $new_conf_raw = '';
9f3d73bc
DM
6749
6750 my $rpcenv = PVE::RPCEnvironment::get();
e8b07b29
FE
6751 my $devinfo = {}; # info about drives included in backup
6752 my $virtdev_hash = {}; # info about allocated drives
9f3d73bc
DM
6753
6754 eval {
6755 # enable interrupts
6756 local $SIG{INT} =
6757 local $SIG{TERM} =
6758 local $SIG{QUIT} =
6759 local $SIG{HUP} =
6760 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
6761
6762 my $cfgfn = "$tmpdir/qemu-server.conf";
6763 my $firewall_config_fn = "$tmpdir/fw.conf";
6764 my $index_fn = "$tmpdir/index.json";
6765
6766 my $cmd = "restore";
6767
6768 my $param = [$pbs_backup_name, "index.json", $index_fn];
6769 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6770 my $index = PVE::Tools::file_get_contents($index_fn);
6771 $index = decode_json($index);
6772
9f3d73bc
DM
6773 foreach my $info (@{$index->{files}}) {
6774 if ($info->{filename} =~ m/^(drive-\S+).img.fidx$/) {
6775 my $devname = $1;
6776 if ($info->{size} =~ m/^(\d+)$/) { # untaint size
6777 $devinfo->{$devname}->{size} = $1;
6778 } else {
6779 die "unable to parse file size in 'index.json' - got '$info->{size}'\n";
6780 }
6781 }
6782 }
6783
4df98f2f
TL
6784 my $is_qemu_server_backup = scalar(
6785 grep { $_->{filename} eq 'qemu-server.conf.blob' } @{$index->{files}}
6786 );
9f3d73bc
DM
6787 if (!$is_qemu_server_backup) {
6788 die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
6789 }
6790 my $has_firewall_config = scalar(grep { $_->{filename} eq 'fw.conf.blob' } @{$index->{files}});
6791
6792 $param = [$pbs_backup_name, "qemu-server.conf", $cfgfn];
6793 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6794
6795 if ($has_firewall_config) {
6796 $param = [$pbs_backup_name, "fw.conf", $firewall_config_fn];
6797 PVE::Storage::PBSPlugin::run_raw_client_cmd($scfg, $storeid, $cmd, $param);
6798
6799 my $pve_firewall_dir = '/etc/pve/firewall';
6800 mkdir $pve_firewall_dir; # make sure the dir exists
6801 PVE::Tools::file_copy($firewall_config_fn, "${pve_firewall_dir}/$vmid.fw");
6802 }
6803
6804 my $fh = IO::File->new($cfgfn, "r") ||
a1cbe55c 6805 die "unable to read qemu-server.conf - $!\n";
9f3d73bc 6806
e8b07b29 6807 $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $storecfg, $fh, $devinfo, $options);
9f3d73bc
DM
6808
6809 # fixme: rate limit?
6810
6811 # create empty/temp config
6812 PVE::Tools::file_set_contents($conffile, "memory: 128\nlock: create");
6813
6814 $restore_cleanup_oldconf->($storecfg, $vmid, $oldconf, $virtdev_hash) if $oldconf;
6815
6816 # allocate volumes
6817 my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
6818
6f94e162
SR
6819 foreach my $virtdev (sort keys %$virtdev_hash) {
6820 my $d = $virtdev_hash->{$virtdev};
6821 next if $d->{is_cloudinit}; # no need to restore cloudinit
9f3d73bc 6822
55c7f9cf 6823 # this fails if storage is unavailable
6f94e162 6824 my $volid = $d->{volid};
6f94e162 6825 my $path = PVE::Storage::path($storecfg, $volid);
9f3d73bc 6826
f9dde219
SR
6827 # for live-restore we only want to preload the efidisk and TPM state
6828 next if $options->{live} && $virtdev ne 'efidisk0' && $virtdev ne 'tpmstate0';
55c7f9cf 6829
21a9ec2a
WB
6830 my @ns_arg;
6831 if (defined(my $ns = $scfg->{namespace})) {
6832 @ns_arg = ('--ns', $ns);
6833 }
6834
6f94e162
SR
6835 my $pbs_restore_cmd = [
6836 '/usr/bin/pbs-restore',
6837 '--repository', $repo,
21a9ec2a 6838 @ns_arg,
6f94e162
SR
6839 $pbs_backup_name,
6840 "$d->{devname}.img.fidx",
6841 $path,
6842 '--verbose',
6843 ];
55fb78aa 6844
6f94e162
SR
6845 push @$pbs_restore_cmd, '--format', $d->{format} if $d->{format};
6846 push @$pbs_restore_cmd, '--keyfile', $keyfile if -e $keyfile;
9f3d73bc 6847
6f94e162
SR
6848 if (PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $volid)) {
6849 push @$pbs_restore_cmd, '--skip-zero';
26731a3c 6850 }
6f94e162
SR
6851
6852 my $dbg_cmdstring = PVE::Tools::cmd2string($pbs_restore_cmd);
6853 print "restore proxmox backup image: $dbg_cmdstring\n";
6854 run_command($pbs_restore_cmd);
9f3d73bc
DM
6855 }
6856
6857 $fh->seek(0, 0) || die "seek failed - $!\n";
6858
9f3d73bc
DM
6859 my $cookie = { netcount => 0 };
6860 while (defined(my $line = <$fh>)) {
c62d7cf5 6861 $new_conf_raw .= restore_update_config_line(
98a4b3fb 6862 $cookie,
98a4b3fb
FE
6863 $map,
6864 $line,
6865 $options->{unique},
6866 );
9f3d73bc
DM
6867 }
6868
6869 $fh->close();
9f3d73bc
DM
6870 };
6871 my $err = $@;
6872
26731a3c 6873 if ($err || !$options->{live}) {
e8b07b29 6874 $restore_deactivate_volumes->($storecfg, $virtdev_hash);
26731a3c 6875 }
9f3d73bc
DM
6876
6877 rmtree $tmpdir;
6878
6879 if ($err) {
e8b07b29 6880 $restore_destroy_volumes->($storecfg, $virtdev_hash);
9f3d73bc
DM
6881 die $err;
6882 }
6883
f7551170
SR
6884 if ($options->{live}) {
6885 # keep lock during live-restore
6886 $new_conf_raw .= "\nlock: create";
6887 }
6888
202a2a0b
FE
6889 my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $options->{override_conf});
6890 PVE::QemuConfig->write_config($vmid, $new_conf);
9f3d73bc
DM
6891
6892 eval { rescan($vmid, 1); };
6893 warn $@ if $@;
26731a3c
SR
6894
6895 PVE::AccessControl::add_vm_to_pool($vmid, $options->{pool}) if $options->{pool};
6896
6897 if ($options->{live}) {
fefd65a1
SR
6898 # enable interrupts
6899 local $SIG{INT} =
6900 local $SIG{TERM} =
6901 local $SIG{QUIT} =
6902 local $SIG{HUP} =
6903 local $SIG{PIPE} = sub { die "got signal ($!) - abort\n"; };
26731a3c 6904
fefd65a1
SR
6905 my $conf = PVE::QemuConfig->load_config($vmid);
6906 die "cannot do live-restore for template\n" if PVE::QemuConfig->is_template($conf);
26731a3c 6907
f9dde219
SR
6908 # these special drives are already restored before start
6909 delete $devinfo->{'drive-efidisk0'};
6910 delete $devinfo->{'drive-tpmstate0-backup'};
2dda626d
DC
6911
6912 my $pbs_opts = {
6913 repo => $repo,
6914 keyfile => $keyfile,
6915 snapshot => $pbs_backup_name,
6916 namespace => $namespace,
6917 };
6918 pbs_live_restore($vmid, $conf, $storecfg, $devinfo, $pbs_opts);
f7551170
SR
6919
6920 PVE::QemuConfig->remove_lock($vmid, "create");
26731a3c
SR
6921 }
6922}
6923
6924sub pbs_live_restore {
2dda626d 6925 my ($vmid, $conf, $storecfg, $restored_disks, $opts) = @_;
26731a3c 6926
88cabb62 6927 print "starting VM for live-restore\n";
2dda626d 6928 print "repository: '$opts->{repo}', snapshot: '$opts->{snapshot}'\n";
26731a3c
SR
6929
6930 my $pbs_backing = {};
8986e36e 6931 for my $ds (keys %$restored_disks) {
26731a3c 6932 $ds =~ m/^drive-(.*)$/;
88cabb62
SR
6933 my $confname = $1;
6934 $pbs_backing->{$confname} = {
2dda626d
DC
6935 repository => $opts->{repo},
6936 snapshot => $opts->{snapshot},
26731a3c
SR
6937 archive => "$ds.img.fidx",
6938 };
2dda626d
DC
6939 $pbs_backing->{$confname}->{keyfile} = $opts->{keyfile} if -e $opts->{keyfile};
6940 $pbs_backing->{$confname}->{namespace} = $opts->{namespace} if defined($opts->{namespace});
88cabb62
SR
6941
6942 my $drive = parse_drive($confname, $conf->{$confname});
6943 print "restoring '$ds' to '$drive->{file}'\n";
26731a3c
SR
6944 }
6945
fd70c843 6946 my $drives_streamed = 0;
26731a3c
SR
6947 eval {
6948 # make sure HA doesn't interrupt our restore by stopping the VM
6949 if (PVE::HA::Config::vm_is_ha_managed($vmid)) {
fd70c843 6950 run_command(['ha-manager', 'set', "vm:$vmid", '--state', 'started']);
26731a3c
SR
6951 }
6952
fd70c843
TL
6953 # start VM with backing chain pointing to PBS backup, environment vars for PBS driver
6954 # in QEMU (PBS_PASSWORD and PBS_FINGERPRINT) are already set by our caller
bfb12678 6955 vm_start_nolock($storecfg, $vmid, $conf, {paused => 1, 'pbs-backing' => $pbs_backing}, {});
26731a3c 6956
26697640
SR
6957 my $qmeventd_fd = register_qmeventd_handle($vmid);
6958
26731a3c
SR
6959 # begin streaming, i.e. data copy from PBS to target disk for every vol,
6960 # this will effectively collapse the backing image chain consisting of
6961 # [target <- alloc-track -> PBS snapshot] to just [target] (alloc-track
6962 # removes itself once all backing images vanish with 'auto-remove=on')
6963 my $jobs = {};
8986e36e 6964 for my $ds (sort keys %$restored_disks) {
26731a3c
SR
6965 my $job_id = "restore-$ds";
6966 mon_cmd($vmid, 'block-stream',
6967 'job-id' => $job_id,
6968 device => "$ds",
6969 );
6970 $jobs->{$job_id} = {};
6971 }
6972
6973 mon_cmd($vmid, 'cont');
6974 qemu_drive_mirror_monitor($vmid, undef, $jobs, 'auto', 0, 'stream');
6975
a09b39f1
TL
6976 print "restore-drive jobs finished successfully, removing all tracking block devices"
6977 ." to disconnect from Proxmox Backup Server\n";
6978
8986e36e 6979 for my $ds (sort keys %$restored_disks) {
26731a3c
SR
6980 mon_cmd($vmid, 'blockdev-del', 'node-name' => "$ds-pbs");
6981 }
26697640
SR
6982
6983 close($qmeventd_fd);
26731a3c
SR
6984 };
6985
6986 my $err = $@;
6987
6988 if ($err) {
8b8893c3 6989 warn "An error occurred during live-restore: $err\n";
26731a3c
SR
6990 _do_vm_stop($storecfg, $vmid, 1, 1, 10, 0, 1);
6991 die "live-restore failed\n";
6992 }
9f3d73bc
DM
6993}
6994
91bd6c90
DM
6995sub restore_vma_archive {
6996 my ($archive, $vmid, $user, $opts, $comp) = @_;
6997
91bd6c90
DM
6998 my $readfrom = $archive;
6999
7c536e11
WB
7000 my $cfg = PVE::Storage::config();
7001 my $commands = [];
7002 my $bwlimit = $opts->{bwlimit};
7003
7004 my $dbg_cmdstring = '';
7005 my $add_pipe = sub {
7006 my ($cmd) = @_;
7007 push @$commands, $cmd;
7008 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
7009 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
91bd6c90 7010 $readfrom = '-';
7c536e11
WB
7011 };
7012
7013 my $input = undef;
7014 if ($archive eq '-') {
7015 $input = '<&STDIN';
7016 } else {
7017 # If we use a backup from a PVE defined storage we also consider that
7018 # storage's rate limit:
7019 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
7020 if (defined($volid)) {
7021 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
7022 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
7023 if ($readlimit) {
7024 print STDERR "applying read rate limit: $readlimit\n";
9444c6e4 7025 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7c536e11
WB
7026 $add_pipe->($cstream);
7027 }
7028 }
7029 }
7030
7031 if ($comp) {
c6d51783
AA
7032 my $info = PVE::Storage::decompressor_info('vma', $comp);
7033 my $cmd = $info->{decompressor};
7034 push @$cmd, $readfrom;
7c536e11 7035 $add_pipe->($cmd);
91bd6c90
DM
7036 }
7037
7038 my $tmpdir = "/var/tmp/vzdumptmp$$";
7039 rmtree $tmpdir;
7040
7041 # disable interrupts (always do cleanups)
5b97ef24
TL
7042 local $SIG{INT} =
7043 local $SIG{TERM} =
7044 local $SIG{QUIT} =
7045 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
91bd6c90
DM
7046
7047 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
7048 POSIX::mkfifo($mapfifo, 0600);
7049 my $fifofh;
808a65b5 7050 my $openfifo = sub { open($fifofh, '>', $mapfifo) or die $! };
91bd6c90 7051
7c536e11 7052 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
91bd6c90
DM
7053
7054 my $oldtimeout;
7055 my $timeout = 5;
7056
e8b07b29
FE
7057 my $devinfo = {}; # info about drives included in backup
7058 my $virtdev_hash = {}; # info about allocated drives
91bd6c90
DM
7059
7060 my $rpcenv = PVE::RPCEnvironment::get();
7061
ffda963f 7062 my $conffile = PVE::QemuConfig->config_file($vmid);
91bd6c90 7063
ae200950 7064 # Note: $oldconf is undef if VM does not exist
ffda963f
FG
7065 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
7066 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
98a4b3fb 7067 my $new_conf_raw = '';
ed221350 7068
7c536e11
WB
7069 my %storage_limits;
7070
91bd6c90 7071 my $print_devmap = sub {
91bd6c90
DM
7072 my $cfgfn = "$tmpdir/qemu-server.conf";
7073
7074 # we can read the config - that is already extracted
7075 my $fh = IO::File->new($cfgfn, "r") ||
a1cbe55c 7076 die "unable to read qemu-server.conf - $!\n";
91bd6c90 7077
6738ab9c 7078 my $fwcfgfn = "$tmpdir/qemu-server.fw";
3457d090
WL
7079 if (-f $fwcfgfn) {
7080 my $pve_firewall_dir = '/etc/pve/firewall';
7081 mkdir $pve_firewall_dir; # make sure the dir exists
7082 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
7083 }
6738ab9c 7084
e8b07b29 7085 $virtdev_hash = $parse_backup_hints->($rpcenv, $user, $cfg, $fh, $devinfo, $opts);
91bd6c90 7086
c8964278
FE
7087 foreach my $info (values %{$virtdev_hash}) {
7088 my $storeid = $info->{storeid};
7089 next if defined($storage_limits{$storeid});
7090
7091 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$storeid], $bwlimit) // 0;
7092 print STDERR "rate limit for storage $storeid: $limit KiB/s\n" if $limit;
7093 $storage_limits{$storeid} = $limit * 1024;
7c536e11
WB
7094 }
7095
91bd6c90 7096 foreach my $devname (keys %$devinfo) {
be190583
DM
7097 die "found no device mapping information for device '$devname'\n"
7098 if !$devinfo->{$devname}->{virtdev};
91bd6c90
DM
7099 }
7100
ed221350 7101 # create empty/temp config
be190583 7102 if ($oldconf) {
ed221350 7103 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
d1e92cf6 7104 $restore_cleanup_oldconf->($cfg, $vmid, $oldconf, $virtdev_hash);
ed221350
DM
7105 }
7106
9f3d73bc
DM
7107 # allocate volumes
7108 my $map = $restore_allocate_devices->($cfg, $virtdev_hash, $vmid);
7109
7110 # print restore information to $fifofh
91bd6c90
DM
7111 foreach my $virtdev (sort keys %$virtdev_hash) {
7112 my $d = $virtdev_hash->{$virtdev};
9f3d73bc
DM
7113 next if $d->{is_cloudinit}; # no need to restore cloudinit
7114
7c536e11 7115 my $storeid = $d->{storeid};
9f3d73bc 7116 my $volid = $d->{volid};
7c536e11
WB
7117
7118 my $map_opts = '';
7119 if (my $limit = $storage_limits{$storeid}) {
7120 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
7121 }
8fd57431 7122
91bd6c90 7123 my $write_zeros = 1;
88240a83 7124 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
91bd6c90
DM
7125 $write_zeros = 0;
7126 }
7127
9f3d73bc 7128 my $path = PVE::Storage::path($cfg, $volid);
87056e18 7129
9f3d73bc 7130 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
91bd6c90 7131
9f3d73bc 7132 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
91bd6c90
DM
7133 }
7134
7135 $fh->seek(0, 0) || die "seek failed - $!\n";
7136
91bd6c90
DM
7137 my $cookie = { netcount => 0 };
7138 while (defined(my $line = <$fh>)) {
c62d7cf5 7139 $new_conf_raw .= restore_update_config_line(
98a4b3fb 7140 $cookie,
98a4b3fb
FE
7141 $map,
7142 $line,
7143 $opts->{unique},
7144 );
91bd6c90
DM
7145 }
7146
7147 $fh->close();
91bd6c90
DM
7148 };
7149
7150 eval {
7151 # enable interrupts
6cb0144a
EK
7152 local $SIG{INT} =
7153 local $SIG{TERM} =
7154 local $SIG{QUIT} =
7155 local $SIG{HUP} =
7156 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
91bd6c90
DM
7157 local $SIG{ALRM} = sub { die "got timeout\n"; };
7158
7159 $oldtimeout = alarm($timeout);
7160
7161 my $parser = sub {
7162 my $line = shift;
7163
7164 print "$line\n";
7165
7166 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
7167 my ($dev_id, $size, $devname) = ($1, $2, $3);
7168 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
7169 } elsif ($line =~ m/^CTIME: /) {
46f58b5f 7170 # we correctly received the vma config, so we can disable
3cf90d7a
DM
7171 # the timeout now for disk allocation (set to 10 minutes, so
7172 # that we always timeout if something goes wrong)
7173 alarm(600);
91bd6c90
DM
7174 &$print_devmap();
7175 print $fifofh "done\n";
7176 my $tmp = $oldtimeout || 0;
7177 $oldtimeout = undef;
7178 alarm($tmp);
7179 close($fifofh);
808a65b5 7180 $fifofh = undef;
91bd6c90
DM
7181 }
7182 };
be190583 7183
7c536e11
WB
7184 print "restore vma archive: $dbg_cmdstring\n";
7185 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
91bd6c90
DM
7186 };
7187 my $err = $@;
7188
7189 alarm($oldtimeout) if $oldtimeout;
7190
e8b07b29 7191 $restore_deactivate_volumes->($cfg, $virtdev_hash);
5f96f4df 7192
808a65b5 7193 close($fifofh) if $fifofh;
91bd6c90 7194 unlink $mapfifo;
9f3d73bc 7195 rmtree $tmpdir;
91bd6c90
DM
7196
7197 if ($err) {
e8b07b29 7198 $restore_destroy_volumes->($cfg, $virtdev_hash);
91bd6c90
DM
7199 die $err;
7200 }
7201
202a2a0b
FE
7202 my $new_conf = $restore_merge_config->($conffile, $new_conf_raw, $opts->{override_conf});
7203 PVE::QemuConfig->write_config($vmid, $new_conf);
ed221350 7204
91bd6c90
DM
7205 eval { rescan($vmid, 1); };
7206 warn $@ if $@;
26731a3c
SR
7207
7208 PVE::AccessControl::add_vm_to_pool($vmid, $opts->{pool}) if $opts->{pool};
91bd6c90
DM
7209}
7210
7211sub restore_tar_archive {
7212 my ($archive, $vmid, $user, $opts) = @_;
7213
202a2a0b
FE
7214 if (scalar(keys $opts->{override_conf}->%*) > 0) {
7215 my $keystring = join(' ', keys $opts->{override_conf}->%*);
7216 die "cannot pass along options ($keystring) when restoring from tar archive\n";
7217 }
7218
9c502e26 7219 if ($archive ne '-') {
ed221350 7220 my $firstfile = tar_archive_read_firstfile($archive);
32e54050 7221 die "ERROR: file '$archive' does not look like a QemuServer vzdump backup\n"
9c502e26
DM
7222 if $firstfile ne 'qemu-server.conf';
7223 }
3e16d5fc 7224
20519efc 7225 my $storecfg = PVE::Storage::config();
ebb55558 7226
4b026937
TL
7227 # avoid zombie disks when restoring over an existing VM -> cleanup first
7228 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
7229 # skiplock=1 because qmrestore has set the 'create' lock itself already
ffda963f 7230 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
b04ea584 7231 destroy_vm($storecfg, $vmid, 1, { lock => 'restore' }) if -f $vmcfgfn;
ed221350 7232
3e16d5fc
DM
7233 my $tocmd = "/usr/lib/qemu-server/qmextract";
7234
2415a446 7235 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
a0d1b1a2 7236 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
3e16d5fc
DM
7237 $tocmd .= ' --prealloc' if $opts->{prealloc};
7238 $tocmd .= ' --info' if $opts->{info};
7239
a0d1b1a2 7240 # tar option "xf" does not autodetect compression when read from STDIN,
9c502e26 7241 # so we pipe to zcat
2415a446
DM
7242 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
7243 PVE::Tools::shellquote("--to-command=$tocmd");
3e16d5fc
DM
7244
7245 my $tmpdir = "/var/tmp/vzdumptmp$$";
7246 mkpath $tmpdir;
7247
7248 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
7249 local $ENV{VZDUMP_VMID} = $vmid;
a0d1b1a2 7250 local $ENV{VZDUMP_USER} = $user;
3e16d5fc 7251
ffda963f 7252 my $conffile = PVE::QemuConfig->config_file($vmid);
98a4b3fb 7253 my $new_conf_raw = '';
3e16d5fc
DM
7254
7255 # disable interrupts (always do cleanups)
6cb0144a
EK
7256 local $SIG{INT} =
7257 local $SIG{TERM} =
7258 local $SIG{QUIT} =
7259 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
3e16d5fc 7260
afdb31d5 7261 eval {
3e16d5fc 7262 # enable interrupts
6cb0144a
EK
7263 local $SIG{INT} =
7264 local $SIG{TERM} =
7265 local $SIG{QUIT} =
7266 local $SIG{HUP} =
7267 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
3e16d5fc 7268
9c502e26
DM
7269 if ($archive eq '-') {
7270 print "extracting archive from STDIN\n";
7271 run_command($cmd, input => "<&STDIN");
7272 } else {
7273 print "extracting archive '$archive'\n";
7274 run_command($cmd);
7275 }
3e16d5fc
DM
7276
7277 return if $opts->{info};
7278
7279 # read new mapping
7280 my $map = {};
7281 my $statfile = "$tmpdir/qmrestore.stat";
7282 if (my $fd = IO::File->new($statfile, "r")) {
7283 while (defined (my $line = <$fd>)) {
7284 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
7285 $map->{$1} = $2 if $1;
7286 } else {
7287 print STDERR "unable to parse line in statfile - $line\n";
7288 }
7289 }
7290 $fd->close();
7291 }
7292
7293 my $confsrc = "$tmpdir/qemu-server.conf";
7294
f7d1505b 7295 my $srcfd = IO::File->new($confsrc, "r") || die "unable to open file '$confsrc'\n";
3e16d5fc 7296
91bd6c90 7297 my $cookie = { netcount => 0 };
3e16d5fc 7298 while (defined (my $line = <$srcfd>)) {
c62d7cf5 7299 $new_conf_raw .= restore_update_config_line(
98a4b3fb 7300 $cookie,
98a4b3fb
FE
7301 $map,
7302 $line,
7303 $opts->{unique},
7304 );
3e16d5fc
DM
7305 }
7306
7307 $srcfd->close();
3e16d5fc 7308 };
7dc7f315 7309 if (my $err = $@) {
ed221350 7310 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
3e16d5fc 7311 die $err;
afdb31d5 7312 }
3e16d5fc
DM
7313
7314 rmtree $tmpdir;
7315
98a4b3fb 7316 PVE::Tools::file_set_contents($conffile, $new_conf_raw);
91bd6c90 7317
ed221350
DM
7318 PVE::Cluster::cfs_update(); # make sure we read new file
7319
91bd6c90
DM
7320 eval { rescan($vmid, 1); };
7321 warn $@ if $@;
3e16d5fc
DM
7322};
7323
65a5ce88 7324sub foreach_storage_used_by_vm {
18bfb361
DM
7325 my ($conf, $func) = @_;
7326
7327 my $sidhash = {};
7328
912792e2 7329 PVE::QemuConfig->foreach_volume($conf, sub {
8ddbcf8b
FG
7330 my ($ds, $drive) = @_;
7331 return if drive_is_cdrom($drive);
18bfb361
DM
7332
7333 my $volid = $drive->{file};
7334
7335 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
be190583 7336 $sidhash->{$sid} = $sid if $sid;
8ddbcf8b 7337 });
18bfb361
DM
7338
7339 foreach my $sid (sort keys %$sidhash) {
7340 &$func($sid);
7341 }
7342}
7343
6c9f59c1
TL
7344my $qemu_snap_storage = {
7345 rbd => 1,
7346};
e5eaa028 7347sub do_snapshots_with_qemu {
9d83932d
SR
7348 my ($storecfg, $volid, $deviceid) = @_;
7349
7350 return if $deviceid =~ m/tpmstate0/;
e5eaa028
WL
7351
7352 my $storage_name = PVE::Storage::parse_volume_id($volid);
8aa2ed7c 7353 my $scfg = $storecfg->{ids}->{$storage_name};
f7d1505b 7354 die "could not find storage '$storage_name'\n" if !defined($scfg);
e5eaa028 7355
8aa2ed7c 7356 if ($qemu_snap_storage->{$scfg->{type}} && !$scfg->{krbd}){
e5eaa028
WL
7357 return 1;
7358 }
7359
7360 if ($volid =~ m/\.(qcow2|qed)$/){
7361 return 1;
7362 }
7363
d1c1af4b 7364 return;
e5eaa028
WL
7365}
7366
4dcc780c 7367sub qga_check_running {
a4938c72 7368 my ($vmid, $nowarn) = @_;
4dcc780c 7369
0a13e08e 7370 eval { mon_cmd($vmid, "guest-ping", timeout => 3); };
4dcc780c 7371 if ($@) {
a4938c72 7372 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
4dcc780c
WL
7373 return 0;
7374 }
7375 return 1;
7376}
7377
04a69bb4
AD
7378sub template_create {
7379 my ($vmid, $conf, $disk) = @_;
7380
04a69bb4 7381 my $storecfg = PVE::Storage::config();
04a69bb4 7382
912792e2 7383 PVE::QemuConfig->foreach_volume($conf, sub {
9cd07842
DM
7384 my ($ds, $drive) = @_;
7385
7386 return if drive_is_cdrom($drive);
7387 return if $disk && $ds ne $disk;
7388
7389 my $volid = $drive->{file};
bbd56097 7390 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
9cd07842 7391
04a69bb4
AD
7392 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
7393 $drive->{file} = $voliddst;
71c58bb7 7394 $conf->{$ds} = print_drive($drive);
ffda963f 7395 PVE::QemuConfig->write_config($vmid, $conf);
04a69bb4 7396 });
04a69bb4
AD
7397}
7398
92bdc3f0
DC
7399sub convert_iscsi_path {
7400 my ($path) = @_;
7401
7402 if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
7403 my $portal = $1;
7404 my $target = $2;
7405 my $lun = $3;
7406
7407 my $initiator_name = get_initiator_name();
7408
7409 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
7410 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
7411 }
7412
7413 die "cannot convert iscsi path '$path', unkown format\n";
7414}
7415
5133de42 7416sub qemu_img_convert {
988e2714 7417 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5133de42
AD
7418
7419 my $storecfg = PVE::Storage::config();
7420 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
7421 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
7422
af1f1ec0 7423 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6bb91c17 7424
af1f1ec0
DC
7425 my $cachemode;
7426 my $src_path;
7427 my $src_is_iscsi = 0;
bdd1feef 7428 my $src_format;
6bb91c17 7429
af1f1ec0
DC
7430 if ($src_storeid) {
7431 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
5133de42 7432 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
af1f1ec0
DC
7433 $src_format = qemu_img_format($src_scfg, $src_volname);
7434 $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
7435 $src_is_iscsi = ($src_path =~ m|^iscsi://|);
7436 $cachemode = 'none' if $src_scfg->{type} eq 'zfspool';
a23d57d5 7437 } elsif (-f $src_volid || -b $src_volid) {
af1f1ec0 7438 $src_path = $src_volid;
e0fd2b2f 7439 if ($src_path =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
af1f1ec0
DC
7440 $src_format = $1;
7441 }
7442 }
5133de42 7443
af1f1ec0 7444 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
5133de42 7445
af1f1ec0
DC
7446 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
7447 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
7448 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
7449 my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
5133de42 7450
af1f1ec0
DC
7451 my $cmd = [];
7452 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
bdd1feef
TL
7453 push @$cmd, '-l', "snapshot.name=$snapname"
7454 if $snapname && $src_format && $src_format eq "qcow2";
af1f1ec0
DC
7455 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
7456 push @$cmd, '-T', $cachemode if defined($cachemode);
7457
7458 if ($src_is_iscsi) {
7459 push @$cmd, '--image-opts';
7460 $src_path = convert_iscsi_path($src_path);
bdd1feef 7461 } elsif ($src_format) {
af1f1ec0
DC
7462 push @$cmd, '-f', $src_format;
7463 }
92bdc3f0 7464
af1f1ec0
DC
7465 if ($dst_is_iscsi) {
7466 push @$cmd, '--target-image-opts';
7467 $dst_path = convert_iscsi_path($dst_path);
7468 } else {
7469 push @$cmd, '-O', $dst_format;
7470 }
92bdc3f0 7471
af1f1ec0 7472 push @$cmd, $src_path;
92bdc3f0 7473
af1f1ec0
DC
7474 if (!$dst_is_iscsi && $is_zero_initialized) {
7475 push @$cmd, "zeroinit:$dst_path";
7476 } else {
7477 push @$cmd, $dst_path;
7478 }
92bdc3f0 7479
af1f1ec0
DC
7480 my $parser = sub {
7481 my $line = shift;
7482 if($line =~ m/\((\S+)\/100\%\)/){
7483 my $percent = $1;
7484 my $transferred = int($size * $percent / 100);
b5e9d97b
TL
7485 my $total_h = render_bytes($size, 1);
7486 my $transferred_h = render_bytes($transferred, 1);
92bdc3f0 7487
6629f976 7488 print "transferred $transferred_h of $total_h ($percent%)\n";
988e2714 7489 }
5133de42 7490
af1f1ec0 7491 };
5133de42 7492
af1f1ec0
DC
7493 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
7494 my $err = $@;
7495 die "copy failed: $err" if $err;
5133de42
AD
7496}
7497
7498sub qemu_img_format {
7499 my ($scfg, $volname) = @_;
7500
e0fd2b2f 7501 if ($scfg->{path} && $volname =~ m/\.($PVE::QemuServer::Drive::QEMU_FORMAT_RE)$/) {
5133de42 7502 return $1;
be190583 7503 } else {
5133de42 7504 return "raw";
5133de42
AD
7505 }
7506}
7507
cfad42af 7508sub qemu_drive_mirror {
bc6c8231 7509 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $completion, $qga, $bwlimit, $src_bitmap) = @_;
cfad42af 7510
5a345967
AD
7511 $jobs = {} if !$jobs;
7512
7513 my $qemu_target;
7514 my $format;
35e4ab04 7515 $jobs->{"drive-$drive"} = {};
152fe752 7516
1e5143de 7517 if ($dst_volid =~ /^nbd:/) {
87955688 7518 $qemu_target = $dst_volid;
5a345967 7519 $format = "nbd";
5a345967 7520 } else {
5a345967
AD
7521 my $storecfg = PVE::Storage::config();
7522 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
7523
7524 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
cfad42af 7525
5a345967 7526 $format = qemu_img_format($dst_scfg, $dst_volname);
21ccdb50 7527
5a345967 7528 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
21ccdb50 7529
5a345967
AD
7530 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
7531 }
988e2714
WB
7532
7533 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
88383920
DM
7534 $opts->{format} = $format if $format;
7535
bc6c8231
FG
7536 if (defined($src_bitmap)) {
7537 $opts->{sync} = 'incremental';
7538 $opts->{bitmap} = $src_bitmap;
7539 print "drive mirror re-using dirty bitmap '$src_bitmap'\n";
7540 }
7541
9fa05d31 7542 if (defined($bwlimit)) {
f6409f61
TL
7543 $opts->{speed} = $bwlimit * 1024;
7544 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
9fa05d31
SI
7545 } else {
7546 print "drive mirror is starting for drive-$drive\n";
7547 }
21ccdb50 7548
6dde5ea2 7549 # if a job already runs for this device we get an error, catch it for cleanup
0a13e08e 7550 eval { mon_cmd($vmid, "drive-mirror", %$opts); };
5a345967
AD
7551 if (my $err = $@) {
7552 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6dde5ea2
TL
7553 warn "$@\n" if $@;
7554 die "mirroring error: $err\n";
5a345967
AD
7555 }
7556
e02fb126 7557 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $completion, $qga);
5a345967
AD
7558}
7559
db1f8b39
FG
7560# $completion can be either
7561# 'complete': wait until all jobs are ready, block-job-complete them (default)
7562# 'cancel': wait until all jobs are ready, block-job-cancel them
7563# 'skip': wait until all jobs are ready, return with block jobs in ready state
9e671722 7564# 'auto': wait until all jobs disappear, only use for jobs which complete automatically
5a345967 7565sub qemu_drive_mirror_monitor {
9e671722 7566 my ($vmid, $vmiddst, $jobs, $completion, $qga, $op) = @_;
e02fb126 7567
db1f8b39 7568 $completion //= 'complete';
9e671722 7569 $op //= "mirror";
2e953867 7570
08ac653f 7571 eval {
5a345967
AD
7572 my $err_complete = 0;
7573
3b56383b 7574 my $starttime = time ();
08ac653f 7575 while (1) {
9e671722 7576 die "block job ('$op') timed out\n" if $err_complete > 300;
5a345967 7577
0a13e08e 7578 my $stats = mon_cmd($vmid, "query-block-jobs");
3b56383b 7579 my $ctime = time();
08ac653f 7580
9e671722 7581 my $running_jobs = {};
0ea24bf0 7582 for my $stat (@$stats) {
9e671722
SR
7583 next if $stat->{type} ne $op;
7584 $running_jobs->{$stat->{device}} = $stat;
5a345967 7585 }
08ac653f 7586
5a345967 7587 my $readycounter = 0;
67fb9de6 7588
0ea24bf0 7589 for my $job_id (sort keys %$jobs) {
1057fc74 7590 my $job = $running_jobs->{$job_id};
5a345967 7591
1057fc74 7592 my $vanished = !defined($job);
0ea24bf0 7593 my $complete = defined($jobs->{$job_id}->{complete}) && $vanished;
9e671722 7594 if($complete || ($vanished && $completion eq 'auto')) {
3b56383b 7595 print "$job_id: $op-job finished\n";
0ea24bf0 7596 delete $jobs->{$job_id};
5a345967
AD
7597 next;
7598 }
7599
1057fc74 7600 die "$job_id: '$op' has been cancelled\n" if !defined($job);
f34ebd52 7601
1057fc74
TL
7602 my $busy = $job->{busy};
7603 my $ready = $job->{ready};
7604 if (my $total = $job->{len}) {
7605 my $transferred = $job->{offset} || 0;
5a345967
AD
7606 my $remaining = $total - $transferred;
7607 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
08ac653f 7608
3b56383b
TL
7609 my $duration = $ctime - $starttime;
7610 my $total_h = render_bytes($total, 1);
7611 my $transferred_h = render_bytes($transferred, 1);
7612
7613 my $status = sprintf(
7614 "transferred $transferred_h of $total_h ($percent%%) in %s",
7615 render_duration($duration),
7616 );
7617
7618 if ($ready) {
7619 if ($busy) {
7620 $status .= ", still busy"; # shouldn't even happen? but mirror is weird
7621 } else {
7622 $status .= ", ready";
7623 }
7624 }
67daf692
TL
7625 print "$job_id: $status\n" if !$jobs->{$job_id}->{ready};
7626 $jobs->{$job_id}->{ready} = $ready;
5a345967 7627 }
f34ebd52 7628
1057fc74 7629 $readycounter++ if $job->{ready};
5a345967 7630 }
b467f79a 7631
5a345967
AD
7632 last if scalar(keys %$jobs) == 0;
7633
7634 if ($readycounter == scalar(keys %$jobs)) {
9e671722
SR
7635 print "all '$op' jobs are ready\n";
7636
7637 # do the complete later (or has already been done)
7638 last if $completion eq 'skip' || $completion eq 'auto';
5a345967
AD
7639
7640 if ($vmiddst && $vmiddst != $vmid) {
1a988fd2
DC
7641 my $agent_running = $qga && qga_check_running($vmid);
7642 if ($agent_running) {
5619e74a 7643 print "freeze filesystem\n";
0a13e08e 7644 eval { mon_cmd($vmid, "guest-fsfreeze-freeze"); };
d6cdfae4 7645 warn $@ if $@;
5619e74a
AD
7646 } else {
7647 print "suspend vm\n";
7648 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
d6cdfae4 7649 warn $@ if $@;
5619e74a
AD
7650 }
7651
5a345967
AD
7652 # if we clone a disk for a new target vm, we don't switch the disk
7653 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
5619e74a 7654
1a988fd2 7655 if ($agent_running) {
5619e74a 7656 print "unfreeze filesystem\n";
0a13e08e 7657 eval { mon_cmd($vmid, "guest-fsfreeze-thaw"); };
d6cdfae4 7658 warn $@ if $@;
5619e74a
AD
7659 } else {
7660 print "resume vm\n";
d6cdfae4
FE
7661 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
7662 warn $@ if $@;
5619e74a
AD
7663 }
7664
2e953867 7665 last;
5a345967
AD
7666 } else {
7667
0ea24bf0 7668 for my $job_id (sort keys %$jobs) {
5a345967 7669 # try to switch the disk if source and destination are on the same guest
0ea24bf0 7670 print "$job_id: Completing block job_id...\n";
5a345967 7671
e02fb126 7672 my $op;
db1f8b39 7673 if ($completion eq 'complete') {
e02fb126 7674 $op = 'block-job-complete';
db1f8b39 7675 } elsif ($completion eq 'cancel') {
e02fb126
ML
7676 $op = 'block-job-cancel';
7677 } else {
7678 die "invalid completion value: $completion\n";
7679 }
0ea24bf0 7680 eval { mon_cmd($vmid, $op, device => $job_id) };
5a345967 7681 if ($@ =~ m/cannot be completed/) {
3b56383b 7682 print "$job_id: block job cannot be completed, trying again.\n";
5a345967
AD
7683 $err_complete++;
7684 }else {
0ea24bf0
TL
7685 print "$job_id: Completed successfully.\n";
7686 $jobs->{$job_id}->{complete} = 1;
5a345967
AD
7687 }
7688 }
2e953867 7689 }
08ac653f 7690 }
08ac653f 7691 sleep 1;
cfad42af 7692 }
08ac653f 7693 };
88383920 7694 my $err = $@;
08ac653f 7695
88383920 7696 if ($err) {
5a345967 7697 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
3b56383b 7698 die "block job ($op) error: $err";
88383920 7699 }
5a345967
AD
7700}
7701
7702sub qemu_blockjobs_cancel {
7703 my ($vmid, $jobs) = @_;
7704
7705 foreach my $job (keys %$jobs) {
bd2d5fe6 7706 print "$job: Cancelling block job\n";
0a13e08e 7707 eval { mon_cmd($vmid, "block-job-cancel", device => $job); };
5a345967
AD
7708 $jobs->{$job}->{cancel} = 1;
7709 }
7710
7711 while (1) {
0a13e08e 7712 my $stats = mon_cmd($vmid, "query-block-jobs");
5a345967
AD
7713
7714 my $running_jobs = {};
7715 foreach my $stat (@$stats) {
7716 $running_jobs->{$stat->{device}} = $stat;
7717 }
7718
7719 foreach my $job (keys %$jobs) {
7720
bd2d5fe6
WB
7721 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
7722 print "$job: Done.\n";
5a345967
AD
7723 delete $jobs->{$job};
7724 }
7725 }
7726
7727 last if scalar(keys %$jobs) == 0;
7728
7729 sleep 1;
cfad42af
AD
7730 }
7731}
7732
152fe752 7733sub clone_disk {
1196086f
FE
7734 my ($storecfg, $source, $dest, $full, $newvollist, $jobs, $completion, $qga, $bwlimit) = @_;
7735
7736 my ($vmid, $running) = $source->@{qw(vmid running)};
25166060 7737 my ($src_drivename, $drive, $snapname) = $source->@{qw(drivename drive snapname)};
1196086f 7738
25166060 7739 my ($newvmid, $dst_drivename, $efisize) = $dest->@{qw(vmid drivename efisize)};
1196086f 7740 my ($storage, $format) = $dest->@{qw(storage format)};
152fe752 7741
5f957592
FE
7742 my $use_drive_mirror = $full && $running && $src_drivename && !$snapname;
7743
25166060
FE
7744 if ($src_drivename && $dst_drivename && $src_drivename ne $dst_drivename) {
7745 die "cloning from/to EFI disk requires EFI disk\n"
7746 if $src_drivename eq 'efidisk0' || $dst_drivename eq 'efidisk0';
7747 die "cloning from/to TPM state requires TPM state\n"
7748 if $src_drivename eq 'tpmstate0' || $dst_drivename eq 'tpmstate0';
5f957592
FE
7749
7750 # This would lead to two device nodes in QEMU pointing to the same backing image!
7751 die "cannot change drive name when cloning disk from/to the same VM\n"
7752 if $use_drive_mirror && $vmid == $newvmid;
25166060
FE
7753 }
7754
1d1f8f9a
FE
7755 die "cannot move TPM state while VM is running\n"
7756 if $use_drive_mirror && $src_drivename eq 'tpmstate0';
7757
152fe752
DM
7758 my $newvolid;
7759
25166060
FE
7760 print "create " . ($full ? 'full' : 'linked') . " clone of drive ";
7761 print "$src_drivename " if $src_drivename;
7762 print "($drive->{file})\n";
7763
152fe752 7764 if (!$full) {
258e646c 7765 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
152fe752
DM
7766 push @$newvollist, $newvolid;
7767 } else {
5a345967 7768
152fe752
DM
7769 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
7770 $storeid = $storage if $storage;
7771
44549149 7772 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
152fe752 7773
931432bd 7774 my $name = undef;
d0abc774 7775 my $size = undef;
7fe8b44c
TL
7776 if (drive_is_cloudinit($drive)) {
7777 $name = "vm-$newvmid-cloudinit";
c997e24a
ML
7778 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7779 if ($scfg->{path}) {
7780 $name .= ".$dst_format";
7781 }
7fe8b44c
TL
7782 $snapname = undef;
7783 $size = PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE;
25166060 7784 } elsif ($dst_drivename eq 'efidisk0') {
7344af7b 7785 $size = $efisize or die "internal error - need to specify EFI disk size\n";
25166060 7786 } elsif ($dst_drivename eq 'tpmstate0') {
5f5aba25 7787 $dst_format = 'raw';
f9dde219 7788 $size = PVE::QemuServer::Drive::TPMSTATE_DISK_SIZE;
d0abc774 7789 } else {
3bae384f 7790 ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 10);
7fe8b44c 7791 }
b5688f69
FE
7792 $newvolid = PVE::Storage::vdisk_alloc(
7793 $storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024)
7794 );
152fe752
DM
7795 push @$newvollist, $newvolid;
7796
3999f370 7797 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
1dbd6d30 7798
7fe8b44c 7799 if (drive_is_cloudinit($drive)) {
1b485263
ML
7800 # when cloning multiple disks (e.g. during clone_vm) it might be the last disk
7801 # if this is the case, we have to complete any block-jobs still there from
7802 # previous drive-mirrors
7803 if (($completion eq 'complete') && (scalar(keys %$jobs) > 0)) {
7804 qemu_drive_mirror_monitor($vmid, $newvmid, $jobs, $completion, $qga);
7805 }
7fe8b44c
TL
7806 goto no_data_clone;
7807 }
7808
988e2714 7809 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
5f957592 7810 if ($use_drive_mirror) {
5f957592
FE
7811 qemu_drive_mirror($vmid, $src_drivename, $newvolid, $newvmid, $sparseinit, $jobs,
7812 $completion, $qga, $bwlimit);
7813 } else {
d189e590 7814 # TODO: handle bwlimits
25166060 7815 if ($dst_drivename eq 'efidisk0') {
818ce80e
DC
7816 # the relevant data on the efidisk may be smaller than the source
7817 # e.g. on RBD/ZFS, so we use dd to copy only the amount
7818 # that is given by the OVMF_VARS.fd
62375438 7819 my $src_path = PVE::Storage::path($storecfg, $drive->{file}, $snapname);
818ce80e 7820 my $dst_path = PVE::Storage::path($storecfg, $newvolid);
fdfdc80e 7821
62375438
FE
7822 my $src_format = (PVE::Storage::parse_volname($storecfg, $drive->{file}))[6];
7823
fdfdc80e
FE
7824 # better for Ceph if block size is not too small, see bug #3324
7825 my $bs = 1024*1024;
7826
62375438 7827 my $cmd = ['qemu-img', 'dd', '-n', '-O', $dst_format];
a9c45bd4
FE
7828
7829 if ($src_format eq 'qcow2' && $snapname) {
7830 die "cannot clone qcow2 EFI disk snapshot - requires QEMU >= 6.2\n"
7831 if !min_version(kvm_user_version(), 6, 2);
7832 push $cmd->@*, '-l', $snapname;
7833 }
62375438
FE
7834 push $cmd->@*, "bs=$bs", "osize=$size", "if=$src_path", "of=$dst_path";
7835 run_command($cmd);
818ce80e
DC
7836 } else {
7837 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
7838 }
be190583 7839 }
152fe752
DM
7840 }
7841
7fe8b44c 7842no_data_clone:
3bae384f 7843 my ($size) = eval { PVE::Storage::volume_size_info($storecfg, $newvolid, 10) };
152fe752 7844
3b53c471
FE
7845 my $disk = dclone($drive);
7846 delete $disk->{format};
152fe752 7847 $disk->{file} = $newvolid;
3bae384f 7848 $disk->{size} = $size if defined($size);
152fe752
DM
7849
7850 return $disk;
7851}
7852
98cfd8b6
AD
7853sub get_running_qemu_version {
7854 my ($vmid) = @_;
0a13e08e 7855 my $res = mon_cmd($vmid, "query-version");
98cfd8b6
AD
7856 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7857}
7858
249c4a6c
AD
7859sub qemu_use_old_bios_files {
7860 my ($machine_type) = @_;
7861
7862 return if !$machine_type;
7863
7864 my $use_old_bios_files = undef;
7865
7866 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7867 $machine_type = $1;
7868 $use_old_bios_files = 1;
7869 } else {
4df98f2f 7870 my $version = extract_version($machine_type, kvm_user_version());
249c4a6c
AD
7871 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7872 # load new efi bios files on migration. So this hack is required to allow
7873 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7874 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
2ea5fb7e 7875 $use_old_bios_files = !min_version($version, 2, 4);
249c4a6c
AD
7876 }
7877
7878 return ($use_old_bios_files, $machine_type);
7879}
7880
818ce80e 7881sub get_efivars_size {
ff84f0e3
FE
7882 my ($conf, $efidisk) = @_;
7883
818ce80e 7884 my $arch = get_vm_arch($conf);
ff84f0e3 7885 $efidisk //= $conf->{efidisk0} ? parse_drive('efidisk0', $conf->{efidisk0}) : undef;
90b20b15
DC
7886 my $smm = PVE::QemuServer::Machine::machine_type_is_q35($conf);
7887 my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk, $smm);
818ce80e
DC
7888 die "uefi vars image '$ovmf_vars' not found\n" if ! -f $ovmf_vars;
7889 return -s $ovmf_vars;
7890}
7891
7892sub update_efidisk_size {
7893 my ($conf) = @_;
7894
7895 return if !defined($conf->{efidisk0});
7896
7897 my $disk = PVE::QemuServer::parse_drive('efidisk0', $conf->{efidisk0});
7898 $disk->{size} = get_efivars_size($conf);
7899 $conf->{efidisk0} = print_drive($disk);
7900
7901 return;
7902}
7903
f9dde219
SR
7904sub update_tpmstate_size {
7905 my ($conf) = @_;
7906
7907 my $disk = PVE::QemuServer::parse_drive('tpmstate0', $conf->{tpmstate0});
7908 $disk->{size} = PVE::QemuServer::Drive::TPMSTATE_DISK_SIZE;
7909 $conf->{tpmstate0} = print_drive($disk);
7910}
7911
90b20b15
DC
7912sub create_efidisk($$$$$$$) {
7913 my ($storecfg, $storeid, $vmid, $fmt, $arch, $efidisk, $smm) = @_;
3e1f1122 7914
90b20b15 7915 my (undef, $ovmf_vars) = get_ovmf_files($arch, $efidisk, $smm);
96ed3574 7916 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
3e1f1122 7917
af1f1ec0
DC
7918 my $vars_size_b = -s $ovmf_vars;
7919 my $vars_size = PVE::Tools::convert_size($vars_size_b, 'b' => 'kb');
3e1f1122
TL
7920 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7921 PVE::Storage::activate_volumes($storecfg, [$volid]);
7922
af1f1ec0 7923 qemu_img_convert($ovmf_vars, $volid, $vars_size_b, undef, 0);
340dbcf7 7924 my ($size) = PVE::Storage::volume_size_info($storecfg, $volid, 3);
3e1f1122 7925
340dbcf7 7926 return ($volid, $size/1024);
3e1f1122
TL
7927}
7928
22de899a
AD
7929sub vm_iothreads_list {
7930 my ($vmid) = @_;
7931
0a13e08e 7932 my $res = mon_cmd($vmid, 'query-iothreads');
22de899a
AD
7933
7934 my $iothreads = {};
7935 foreach my $iothread (@$res) {
7936 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
7937 }
7938
7939 return $iothreads;
7940}
7941
ee034f5c
AD
7942sub scsihw_infos {
7943 my ($conf, $drive) = @_;
7944
7945 my $maxdev = 0;
7946
7fe1b688 7947 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
ee034f5c 7948 $maxdev = 7;
a1511b3c 7949 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
ee034f5c
AD
7950 $maxdev = 1;
7951 } else {
7952 $maxdev = 256;
7953 }
7954
7955 my $controller = int($drive->{index} / $maxdev);
4df98f2f
TL
7956 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single')
7957 ? "virtioscsi"
7958 : "scsihw";
ee034f5c
AD
7959
7960 return ($maxdev, $controller, $controller_prefix);
7961}
a1511b3c 7962
4317f69f
AD
7963sub windows_version {
7964 my ($ostype) = @_;
7965
7966 return 0 if !$ostype;
7967
7968 my $winversion = 0;
7969
7970 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7971 $winversion = 5;
7972 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7973 $winversion = 6;
7974 } elsif ($ostype =~ m/^win(\d+)$/) {
7975 $winversion = $1;
7976 }
7977
7978 return $winversion;
7979}
7980
44549149
EK
7981sub resolve_dst_disk_format {
7982 my ($storecfg, $storeid, $src_volname, $format) = @_;
7983 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
7984
7985 if (!$format) {
7986 # if no target format is specified, use the source disk format as hint
7987 if ($src_volname) {
7988 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7989 $format = qemu_img_format($scfg, $src_volname);
7990 } else {
7991 return $defFormat;
7992 }
7993 }
7994
7995 # test if requested format is supported - else use default
7996 my $supported = grep { $_ eq $format } @$validFormats;
7997 $format = $defFormat if !$supported;
7998 return $format;
7999}
8000
66cebc46
DC
8001# NOTE: if this logic changes, please update docs & possibly gui logic
8002sub find_vmstate_storage {
8003 my ($conf, $storecfg) = @_;
8004
8005 # first, return storage from conf if set
8006 return $conf->{vmstatestorage} if $conf->{vmstatestorage};
8007
8008 my ($target, $shared, $local);
8009
8010 foreach_storage_used_by_vm($conf, sub {
8011 my ($sid) = @_;
8012 my $scfg = PVE::Storage::storage_config($storecfg, $sid);
8013 my $dst = $scfg->{shared} ? \$shared : \$local;
8014 $$dst = $sid if !$$dst || $scfg->{path}; # prefer file based storage
8015 });
8016
8017 # second, use shared storage where VM has at least one disk
8018 # third, use local storage where VM has at least one disk
8019 # fall back to local storage
8020 $target = $shared // $local // 'local';
8021
8022 return $target;
8023}
8024
6ee499ff 8025sub generate_uuid {
ae2fcb3b
EK
8026 my ($uuid, $uuid_str);
8027 UUID::generate($uuid);
8028 UUID::unparse($uuid, $uuid_str);
6ee499ff
DC
8029 return $uuid_str;
8030}
8031
8032sub generate_smbios1_uuid {
8033 return "uuid=".generate_uuid();
ae2fcb3b
EK
8034}
8035
9c152e87
TL
8036sub nbd_stop {
8037 my ($vmid) = @_;
8038
0a13e08e 8039 mon_cmd($vmid, 'nbd-server-stop');
9c152e87
TL
8040}
8041
dae98db9
DC
8042sub create_reboot_request {
8043 my ($vmid) = @_;
8044 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
8045 or die "failed to create reboot trigger file: $!\n";
8046 close($fh);
8047}
8048
8049sub clear_reboot_request {
8050 my ($vmid) = @_;
8051 my $path = "/run/qemu-server/$vmid.reboot";
8052 my $res = 0;
8053
8054 $res = unlink($path);
8055 die "could not remove reboot request for $vmid: $!"
8056 if !$res && $! != POSIX::ENOENT;
8057
8058 return $res;
8059}
8060
5cfa9f5f
SR
8061sub bootorder_from_legacy {
8062 my ($conf, $bootcfg) = @_;
8063
8064 my $boot = $bootcfg->{legacy} || $boot_fmt->{legacy}->{default};
8065 my $bootindex_hash = {};
8066 my $i = 1;
8067 foreach my $o (split(//, $boot)) {
8068 $bootindex_hash->{$o} = $i*100;
8069 $i++;
8070 }
8071
8072 my $bootorder = {};
8073
8074 PVE::QemuConfig->foreach_volume($conf, sub {
8075 my ($ds, $drive) = @_;
8076
8077 if (drive_is_cdrom ($drive, 1)) {
8078 if ($bootindex_hash->{d}) {
8079 $bootorder->{$ds} = $bootindex_hash->{d};
8080 $bootindex_hash->{d} += 1;
8081 }
8082 } elsif ($bootindex_hash->{c}) {
8083 $bootorder->{$ds} = $bootindex_hash->{c}
8084 if $conf->{bootdisk} && $conf->{bootdisk} eq $ds;
8085 $bootindex_hash->{c} += 1;
8086 }
8087 });
8088
8089 if ($bootindex_hash->{n}) {
8090 for (my $i = 0; $i < $MAX_NETS; $i++) {
8091 my $netname = "net$i";
8092 next if !$conf->{$netname};
8093 $bootorder->{$netname} = $bootindex_hash->{n};
8094 $bootindex_hash->{n} += 1;
8095 }
8096 }
8097
8098 return $bootorder;
8099}
8100
8101# Generate default device list for 'boot: order=' property. Matches legacy
8102# default boot order, but with explicit device names. This is important, since
8103# the fallback for when neither 'order' nor the old format is specified relies
8104# on 'bootorder_from_legacy' above, and it would be confusing if this diverges.
8105sub get_default_bootdevices {
8106 my ($conf) = @_;
8107
8108 my @ret = ();
8109
8110 # harddisk
8111 my $first = PVE::QemuServer::Drive::resolve_first_disk($conf, 0);
8112 push @ret, $first if $first;
8113
8114 # cdrom
8115 $first = PVE::QemuServer::Drive::resolve_first_disk($conf, 1);
8116 push @ret, $first if $first;
8117
8118 # network
8119 for (my $i = 0; $i < $MAX_NETS; $i++) {
8120 my $netname = "net$i";
8121 next if !$conf->{$netname};
8122 push @ret, $netname;
8123 last;
8124 }
8125
8126 return \@ret;
8127}
8128
e5d611c3
TL
8129sub device_bootorder {
8130 my ($conf) = @_;
8131
8132 return bootorder_from_legacy($conf) if !defined($conf->{boot});
8133
8134 my $boot = parse_property_string($boot_fmt, $conf->{boot});
8135
8136 my $bootorder = {};
8137 if (!defined($boot) || $boot->{legacy}) {
8138 $bootorder = bootorder_from_legacy($conf, $boot);
8139 } elsif ($boot->{order}) {
8140 my $i = 100; # start at 100 to allow user to insert devices before us with -args
8141 for my $dev (PVE::Tools::split_list($boot->{order})) {
8142 $bootorder->{$dev} = $i++;
8143 }
8144 }
8145
8146 return $bootorder;
8147}
8148
65911545
SR
8149sub register_qmeventd_handle {
8150 my ($vmid) = @_;
8151
8152 my $fh;
8153 my $peer = "/var/run/qmeventd.sock";
8154 my $count = 0;
8155
8156 for (;;) {
8157 $count++;
8158 $fh = IO::Socket::UNIX->new(Peer => $peer, Blocking => 0, Timeout => 1);
8159 last if $fh;
8160 if ($! != EINTR && $! != EAGAIN) {
8161 die "unable to connect to qmeventd socket (vmid: $vmid) - $!\n";
8162 }
8163 if ($count > 4) {
8164 die "unable to connect to qmeventd socket (vmid: $vmid) - timeout "
8165 . "after $count retries\n";
8166 }
8167 usleep(25000);
8168 }
8169
8170 # send handshake to mark VM as backing up
8171 print $fh to_json({vzdump => {vmid => "$vmid"}});
8172
8173 # return handle to be closed later when inhibit is no longer required
8174 return $fh;
8175}
8176
65e866e5
DM
8177# bash completion helper
8178
8179sub complete_backup_archives {
8180 my ($cmdname, $pname, $cvalue) = @_;
8181
8182 my $cfg = PVE::Storage::config();
8183
8184 my $storeid;
8185
8186 if ($cvalue =~ m/^([^:]+):/) {
8187 $storeid = $1;
8188 }
8189
8190 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
8191
8192 my $res = [];
8193 foreach my $id (keys %$data) {
8194 foreach my $item (@{$data->{$id}}) {
f43a4f12 8195 next if $item->{format} !~ m/^vma\.(${\PVE::Storage::Plugin::COMPRESSOR_RE})$/;
65e866e5
DM
8196 push @$res, $item->{volid} if defined($item->{volid});
8197 }
8198 }
8199
8200 return $res;
8201}
8202
8203my $complete_vmid_full = sub {
8204 my ($running) = @_;
8205
8206 my $idlist = vmstatus();
8207
8208 my $res = [];
8209
8210 foreach my $id (keys %$idlist) {
8211 my $d = $idlist->{$id};
8212 if (defined($running)) {
8213 next if $d->{template};
8214 next if $running && $d->{status} ne 'running';
8215 next if !$running && $d->{status} eq 'running';
8216 }
8217 push @$res, $id;
8218
8219 }
8220 return $res;
8221};
8222
8223sub complete_vmid {
8224 return &$complete_vmid_full();
8225}
8226
8227sub complete_vmid_stopped {
8228 return &$complete_vmid_full(0);
8229}
8230
8231sub complete_vmid_running {
8232 return &$complete_vmid_full(1);
8233}
8234
335af808
DM
8235sub complete_storage {
8236
8237 my $cfg = PVE::Storage::config();
8238 my $ids = $cfg->{ids};
8239
8240 my $res = [];
8241 foreach my $sid (keys %$ids) {
8242 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
c4c844ef 8243 next if !$ids->{$sid}->{content}->{images};
335af808
DM
8244 push @$res, $sid;
8245 }
8246
8247 return $res;
8248}
8249
255e9c54
AL
8250sub complete_migration_storage {
8251 my ($cmd, $param, $current_value, $all_args) = @_;
8252
8253 my $targetnode = @$all_args[1];
8254
8255 my $cfg = PVE::Storage::config();
8256 my $ids = $cfg->{ids};
8257
8258 my $res = [];
8259 foreach my $sid (keys %$ids) {
8260 next if !PVE::Storage::storage_check_enabled($cfg, $sid, $targetnode, 1);
8261 next if !$ids->{$sid}->{content}->{images};
8262 push @$res, $sid;
8263 }
8264
8265 return $res;
8266}
8267
b08c37c3
DC
8268sub vm_is_paused {
8269 my ($vmid) = @_;
8270 my $qmpstatus = eval {
8271 PVE::QemuConfig::assert_config_exists_on_node($vmid);
8272 mon_cmd($vmid, "query-status");
8273 };
8274 warn "$@\n" if $@;
8275 return $qmpstatus && $qmpstatus->{status} eq "paused";
8276}
8277
3f11f0d7
LS
8278sub check_volume_storage_type {
8279 my ($storecfg, $vol) = @_;
8280
8281 my ($storeid, $volname) = PVE::Storage::parse_volume_id($vol);
8282 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
8283 my ($vtype) = PVE::Storage::parse_volname($storecfg, $vol);
8284
8285 die "storage '$storeid' does not support content-type '$vtype'\n"
8286 if !$scfg->{content}->{$vtype};
8287
8288 return 1;
8289}
8290
1e3baf05 82911;