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