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