]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
qmreboot: clear reboot request if reboot fails
[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 {
b04ea584 2553 my ($storecfg, $vmid, $skiplock, $replacement_conf) = @_;
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 2596
b04ea584
TL
2597 if (defined $replacement_conf) {
2598 PVE::LXC::Config->write_config($vmid, $replacement_conf);
dfda979e
DJ
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 {
66026117 5797 eval {
165411f0 5798
66026117
OB
5799 # only reboot if running, as qmeventd starts it again on a stop event
5800 return if !check_running($vmid);
165411f0 5801
66026117 5802 create_reboot_request($vmid);
165411f0 5803
66026117
OB
5804 my $storecfg = PVE::Storage::config();
5805 _do_vm_stop($storecfg, $vmid, undef, undef, $timeout, 1);
165411f0 5806
66026117
OB
5807 };
5808 if (my $err = $@) {
5809 # clear reboot request if reboot fails for some reason
5810 clear_reboot_request($vmid);
5811 die $err;
5812 }
165411f0
DC
5813 });
5814}
5815
1e3baf05 5816sub vm_suspend {
48b4cdc2 5817 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
159719e5
DC
5818
5819 my $conf;
5820 my $path;
5821 my $storecfg;
5822 my $vmstate;
1e3baf05 5823
ffda963f 5824 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5825
159719e5 5826 $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5827
159719e5 5828 my $is_backing_up = PVE::QemuConfig->has_lock($conf, 'backup');
e79706d4 5829 PVE::QemuConfig->check_lock($conf)
159719e5
DC
5830 if !($skiplock || $is_backing_up);
5831
5832 die "cannot suspend to disk during backup\n"
5833 if $is_backing_up && $includestate;
bcb7c9cf 5834
159719e5
DC
5835 if ($includestate) {
5836 $conf->{lock} = 'suspending';
5837 my $date = strftime("%Y-%m-%d", localtime(time()));
5838 $storecfg = PVE::Storage::config();
48b4cdc2 5839 $vmstate = PVE::QemuConfig->__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
159719e5
DC
5840 $path = PVE::Storage::path($storecfg, $vmstate);
5841 PVE::QemuConfig->write_config($vmid, $conf);
5842 } else {
5843 vm_mon_cmd($vmid, "stop");
5844 }
1e3baf05 5845 });
159719e5
DC
5846
5847 if ($includestate) {
5848 # save vm state
5849 PVE::Storage::activate_volumes($storecfg, [$vmstate]);
5850
5851 eval {
5852 vm_mon_cmd($vmid, "savevm-start", statefile => $path);
5853 for(;;) {
5854 my $state = vm_mon_cmd_nocheck($vmid, "query-savevm");
5855 if (!$state->{status}) {
5856 die "savevm not active\n";
5857 } elsif ($state->{status} eq 'active') {
5858 sleep(1);
5859 next;
5860 } elsif ($state->{status} eq 'completed') {
b0a9a385 5861 print "State saved, quitting\n";
159719e5
DC
5862 last;
5863 } elsif ($state->{status} eq 'failed' && $state->{error}) {
5864 die "query-savevm failed with error '$state->{error}'\n"
5865 } else {
5866 die "query-savevm returned status '$state->{status}'\n";
5867 }
5868 }
5869 };
5870 my $err = $@;
5871
5872 PVE::QemuConfig->lock_config($vmid, sub {
5873 $conf = PVE::QemuConfig->load_config($vmid);
5874 if ($err) {
5875 # cleanup, but leave suspending lock, to indicate something went wrong
5876 eval {
5877 vm_mon_cmd($vmid, "savevm-end");
5878 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5879 PVE::Storage::vdisk_free($storecfg, $vmstate);
5880 delete $conf->@{qw(vmstate runningmachine)};
5881 PVE::QemuConfig->write_config($vmid, $conf);
5882 };
5883 warn $@ if $@;
5884 die $err;
5885 }
5886
5887 die "lock changed unexpectedly\n"
5888 if !PVE::QemuConfig->has_lock($conf, 'suspending');
5889
5890 vm_qmp_command($vmid, { execute => "quit" });
5891 $conf->{lock} = 'suspended';
5892 PVE::QemuConfig->write_config($vmid, $conf);
5893 });
5894 }
1e3baf05
DM
5895}
5896
5897sub vm_resume {
289e0b85 5898 my ($vmid, $skiplock, $nocheck) = @_;
1e3baf05 5899
ffda963f 5900 PVE::QemuConfig->lock_config($vmid, sub {
3e24733b
FG
5901 my $vm_mon_cmd = $nocheck ? \&vm_mon_cmd_nocheck : \&vm_mon_cmd;
5902 my $res = $vm_mon_cmd->($vmid, 'query-status');
c2786bed
DC
5903 my $resume_cmd = 'cont';
5904
5905 if ($res->{status} && $res->{status} eq 'suspended') {
5906 $resume_cmd = 'system_wakeup';
5907 }
5908
289e0b85 5909 if (!$nocheck) {
1e3baf05 5910
ffda963f 5911 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5912
e79706d4
FG
5913 PVE::QemuConfig->check_lock($conf)
5914 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
289e0b85 5915 }
3e24733b
FG
5916
5917 $vm_mon_cmd->($vmid, $resume_cmd);
1e3baf05
DM
5918 });
5919}
5920
5fdbe4f0
DM
5921sub vm_sendkey {
5922 my ($vmid, $skiplock, $key) = @_;
1e3baf05 5923
ffda963f 5924 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5925
ffda963f 5926 my $conf = PVE::QemuConfig->load_config($vmid);
f5eb281a 5927
7b7c6d1b 5928 # there is no qmp command, so we use the human monitor command
d30820d6
DC
5929 my $res = vm_human_monitor_command($vmid, "sendkey $key");
5930 die $res if $res ne '';
1e3baf05
DM
5931 });
5932}
5933
3e16d5fc
DM
5934# vzdump restore implementaion
5935
ed221350 5936sub tar_archive_read_firstfile {
3e16d5fc 5937 my $archive = shift;
afdb31d5 5938
3e16d5fc
DM
5939 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
5940
5941 # try to detect archive type first
387ba257 5942 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
3e16d5fc 5943 die "unable to open file '$archive'\n";
387ba257 5944 my $firstfile = <$fh>;
3e16d5fc 5945 kill 15, $pid;
387ba257 5946 close $fh;
3e16d5fc
DM
5947
5948 die "ERROR: archive contaions no data\n" if !$firstfile;
5949 chomp $firstfile;
5950
5951 return $firstfile;
5952}
5953
ed221350
DM
5954sub tar_restore_cleanup {
5955 my ($storecfg, $statfile) = @_;
3e16d5fc
DM
5956
5957 print STDERR "starting cleanup\n";
5958
5959 if (my $fd = IO::File->new($statfile, "r")) {
5960 while (defined(my $line = <$fd>)) {
5961 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5962 my $volid = $2;
5963 eval {
5964 if ($volid =~ m|^/|) {
5965 unlink $volid || die 'unlink failed\n';
5966 } else {
ed221350 5967 PVE::Storage::vdisk_free($storecfg, $volid);
3e16d5fc 5968 }
afdb31d5 5969 print STDERR "temporary volume '$volid' sucessfuly removed\n";
3e16d5fc
DM
5970 };
5971 print STDERR "unable to cleanup '$volid' - $@" if $@;
5972 } else {
5973 print STDERR "unable to parse line in statfile - $line";
afdb31d5 5974 }
3e16d5fc
DM
5975 }
5976 $fd->close();
5977 }
5978}
5979
5980sub restore_archive {
a0d1b1a2 5981 my ($archive, $vmid, $user, $opts) = @_;
3e16d5fc 5982
91bd6c90
DM
5983 my $format = $opts->{format};
5984 my $comp;
5985
5986 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5987 $format = 'tar' if !$format;
5988 $comp = 'gzip';
5989 } elsif ($archive =~ m/\.tar$/) {
5990 $format = 'tar' if !$format;
5991 } elsif ($archive =~ m/.tar.lzo$/) {
5992 $format = 'tar' if !$format;
5993 $comp = 'lzop';
5994 } elsif ($archive =~ m/\.vma$/) {
5995 $format = 'vma' if !$format;
5996 } elsif ($archive =~ m/\.vma\.gz$/) {
5997 $format = 'vma' if !$format;
5998 $comp = 'gzip';
5999 } elsif ($archive =~ m/\.vma\.lzo$/) {
6000 $format = 'vma' if !$format;
6001 $comp = 'lzop';
6002 } else {
6003 $format = 'vma' if !$format; # default
6004 }
6005
6006 # try to detect archive format
6007 if ($format eq 'tar') {
6008 return restore_tar_archive($archive, $vmid, $user, $opts);
6009 } else {
6010 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
6011 }
6012}
6013
6014sub restore_update_config_line {
6015 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
6016
6017 return if $line =~ m/^\#qmdump\#/;
6018 return if $line =~ m/^\#vzdump\#/;
6019 return if $line =~ m/^lock:/;
6020 return if $line =~ m/^unused\d+:/;
6021 return if $line =~ m/^parent:/;
6022
b5b99790 6023 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
91bd6c90
DM
6024 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6025 # try to convert old 1.X settings
6026 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6027 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
6028 my ($model, $macaddr) = split(/\=/, $devconfig);
b5b99790 6029 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
91bd6c90
DM
6030 my $net = {
6031 model => $model,
6032 bridge => "vmbr$ind",
6033 macaddr => $macaddr,
6034 };
6035 my $netstr = print_net($net);
6036
6037 print $outfd "net$cookie->{netcount}: $netstr\n";
6038 $cookie->{netcount}++;
6039 }
6040 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6041 my ($id, $netstr) = ($1, $2);
6042 my $net = parse_net($netstr);
b5b99790 6043 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
91bd6c90
DM
6044 $netstr = print_net($net);
6045 print $outfd "$id: $netstr\n";
6470743f 6046 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
91bd6c90 6047 my $virtdev = $1;
907ea891 6048 my $value = $3;
d9faf790
WB
6049 my $di = parse_drive($virtdev, $value);
6050 if (defined($di->{backup}) && !$di->{backup}) {
91bd6c90 6051 print $outfd "#$line";
c0f7406e 6052 } elsif ($map->{$virtdev}) {
8fd57431 6053 delete $di->{format}; # format can change on restore
91bd6c90 6054 $di->{file} = $map->{$virtdev};
ed221350 6055 $value = print_drive($vmid, $di);
91bd6c90
DM
6056 print $outfd "$virtdev: $value\n";
6057 } else {
6058 print $outfd $line;
6059 }
1a0c2f03 6060 } elsif (($line =~ m/^vmgenid: (.*)/)) {
babecffe 6061 my $vmgenid = $1;
6ee499ff 6062 if ($vmgenid ne '0') {
1a0c2f03 6063 # always generate a new vmgenid if there was a valid one setup
6ee499ff
DC
6064 $vmgenid = generate_uuid();
6065 }
1a0c2f03 6066 print $outfd "vmgenid: $vmgenid\n";
19a5dd55
WL
6067 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6068 my ($uuid, $uuid_str);
6069 UUID::generate($uuid);
6070 UUID::unparse($uuid, $uuid_str);
6071 my $smbios1 = parse_smbios1($2);
6072 $smbios1->{uuid} = $uuid_str;
6073 print $outfd $1.print_smbios1($smbios1)."\n";
91bd6c90
DM
6074 } else {
6075 print $outfd $line;
6076 }
6077}
6078
6079sub scan_volids {
6080 my ($cfg, $vmid) = @_;
6081
6082 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid);
6083
6084 my $volid_hash = {};
6085 foreach my $storeid (keys %$info) {
6086 foreach my $item (@{$info->{$storeid}}) {
6087 next if !($item->{volid} && $item->{size});
5996a936 6088 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
91bd6c90
DM
6089 $volid_hash->{$item->{volid}} = $item;
6090 }
6091 }
6092
6093 return $volid_hash;
6094}
6095
77019edf
WB
6096sub is_volume_in_use {
6097 my ($storecfg, $conf, $skip_drive, $volid) = @_;
a8e2f942 6098
77019edf 6099 my $path = PVE::Storage::path($storecfg, $volid);
a8e2f942
DM
6100
6101 my $scan_config = sub {
6102 my ($cref, $snapname) = @_;
6103
6104 foreach my $key (keys %$cref) {
6105 my $value = $cref->{$key};
74479ee9 6106 if (is_valid_drivename($key)) {
a8e2f942
DM
6107 next if $skip_drive && $key eq $skip_drive;
6108 my $drive = parse_drive($key, $value);
6109 next if !$drive || !$drive->{file} || drive_is_cdrom($drive);
77019edf 6110 return 1 if $volid eq $drive->{file};
a8e2f942 6111 if ($drive->{file} =~ m!^/!) {
77019edf 6112 return 1 if $drive->{file} eq $path;
a8e2f942
DM
6113 } else {
6114 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file}, 1);
6115 next if !$storeid;
6116 my $scfg = PVE::Storage::storage_config($storecfg, $storeid, 1);
6117 next if !$scfg;
77019edf 6118 return 1 if $path eq PVE::Storage::path($storecfg, $drive->{file}, $snapname);
a8e2f942
DM
6119 }
6120 }
6121 }
77019edf
WB
6122
6123 return 0;
a8e2f942
DM
6124 };
6125
77019edf 6126 return 1 if &$scan_config($conf);
a8e2f942
DM
6127
6128 undef $skip_drive;
6129
77019edf
WB
6130 foreach my $snapname (keys %{$conf->{snapshots}}) {
6131 return 1 if &$scan_config($conf->{snapshots}->{$snapname}, $snapname);
a8e2f942
DM
6132 }
6133
77019edf 6134 return 0;
a8e2f942
DM
6135}
6136
91bd6c90
DM
6137sub update_disksize {
6138 my ($vmid, $conf, $volid_hash) = @_;
be190583 6139
91bd6c90 6140 my $changes;
53b81297 6141 my $prefix = "VM $vmid:";
91bd6c90 6142
c449137a
DC
6143 # used and unused disks
6144 my $referenced = {};
91bd6c90 6145
5996a936
DM
6146 # Note: it is allowed to define multiple storages with same path (alias), so
6147 # we need to check both 'volid' and real 'path' (two different volid can point
6148 # to the same path).
6149
c449137a 6150 my $referencedpath = {};
be190583 6151
91bd6c90
DM
6152 # update size info
6153 foreach my $opt (keys %$conf) {
74479ee9 6154 if (is_valid_drivename($opt)) {
ed221350 6155 my $drive = parse_drive($opt, $conf->{$opt});
91bd6c90
DM
6156 my $volid = $drive->{file};
6157 next if !$volid;
6158
c449137a 6159 $referenced->{$volid} = 1;
be190583 6160 if ($volid_hash->{$volid} &&
5996a936 6161 (my $path = $volid_hash->{$volid}->{path})) {
c449137a 6162 $referencedpath->{$path} = 1;
5996a936 6163 }
91bd6c90 6164
ed221350 6165 next if drive_is_cdrom($drive);
91bd6c90
DM
6166 next if !$volid_hash->{$volid};
6167
6168 $drive->{size} = $volid_hash->{$volid}->{size};
7a907ce6
DM
6169 my $new = print_drive($vmid, $drive);
6170 if ($new ne $conf->{$opt}) {
6171 $changes = 1;
6172 $conf->{$opt} = $new;
53b81297 6173 print "$prefix update disk '$opt' information.\n";
7a907ce6 6174 }
91bd6c90
DM
6175 }
6176 }
6177
5996a936
DM
6178 # remove 'unusedX' entry if volume is used
6179 foreach my $opt (keys %$conf) {
6180 next if $opt !~ m/^unused\d+$/;
6181 my $volid = $conf->{$opt};
6182 my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
c449137a 6183 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
53b81297 6184 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5996a936
DM
6185 $changes = 1;
6186 delete $conf->{$opt};
6187 }
c449137a
DC
6188
6189 $referenced->{$volid} = 1;
6190 $referencedpath->{$path} = 1 if $path;
5996a936
DM
6191 }
6192
91bd6c90
DM
6193 foreach my $volid (sort keys %$volid_hash) {
6194 next if $volid =~ m/vm-$vmid-state-/;
c449137a 6195 next if $referenced->{$volid};
5996a936
DM
6196 my $path = $volid_hash->{$volid}->{path};
6197 next if !$path; # just to be sure
c449137a 6198 next if $referencedpath->{$path};
91bd6c90 6199 $changes = 1;
53b81297
TL
6200 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
6201 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
c449137a 6202 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
91bd6c90
DM
6203 }
6204
6205 return $changes;
6206}
6207
6208sub rescan {
9224dcee 6209 my ($vmid, $nolock, $dryrun) = @_;
91bd6c90 6210
20519efc 6211 my $cfg = PVE::Storage::config();
91bd6c90 6212
b9a1a3ab
TL
6213 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
6214 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
4771526a
AA
6215 foreach my $stor (keys %{$cfg->{ids}}) {
6216 delete($cfg->{ids}->{$stor}) if ! $cfg->{ids}->{$stor}->{content}->{images};
6217 }
6218
53b81297 6219 print "rescan volumes...\n";
91bd6c90
DM
6220 my $volid_hash = scan_volids($cfg, $vmid);
6221
6222 my $updatefn = sub {
6223 my ($vmid) = @_;
6224
ffda963f 6225 my $conf = PVE::QemuConfig->load_config($vmid);
be190583 6226
ffda963f 6227 PVE::QemuConfig->check_lock($conf);
91bd6c90 6228
03da3f0d
DM
6229 my $vm_volids = {};
6230 foreach my $volid (keys %$volid_hash) {
6231 my $info = $volid_hash->{$volid};
6232 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
6233 }
6234
6235 my $changes = update_disksize($vmid, $conf, $vm_volids);
91bd6c90 6236
9224dcee 6237 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
91bd6c90
DM
6238 };
6239
6240 if (defined($vmid)) {
6241 if ($nolock) {
6242 &$updatefn($vmid);
6243 } else {
ffda963f 6244 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
91bd6c90
DM
6245 }
6246 } else {
6247 my $vmlist = config_list();
6248 foreach my $vmid (keys %$vmlist) {
6249 if ($nolock) {
6250 &$updatefn($vmid);
6251 } else {
ffda963f 6252 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
be190583 6253 }
91bd6c90
DM
6254 }
6255 }
6256}
6257
6258sub restore_vma_archive {
6259 my ($archive, $vmid, $user, $opts, $comp) = @_;
6260
91bd6c90
DM
6261 my $readfrom = $archive;
6262
7c536e11
WB
6263 my $cfg = PVE::Storage::config();
6264 my $commands = [];
6265 my $bwlimit = $opts->{bwlimit};
6266
6267 my $dbg_cmdstring = '';
6268 my $add_pipe = sub {
6269 my ($cmd) = @_;
6270 push @$commands, $cmd;
6271 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6272 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
91bd6c90 6273 $readfrom = '-';
7c536e11
WB
6274 };
6275
6276 my $input = undef;
6277 if ($archive eq '-') {
6278 $input = '<&STDIN';
6279 } else {
6280 # If we use a backup from a PVE defined storage we also consider that
6281 # storage's rate limit:
6282 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
6283 if (defined($volid)) {
6284 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
6285 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
6286 if ($readlimit) {
6287 print STDERR "applying read rate limit: $readlimit\n";
9444c6e4 6288 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7c536e11
WB
6289 $add_pipe->($cstream);
6290 }
6291 }
6292 }
6293
6294 if ($comp) {
6295 my $cmd;
91bd6c90 6296 if ($comp eq 'gzip') {
7c536e11 6297 $cmd = ['zcat', $readfrom];
91bd6c90 6298 } elsif ($comp eq 'lzop') {
7c536e11 6299 $cmd = ['lzop', '-d', '-c', $readfrom];
91bd6c90
DM
6300 } else {
6301 die "unknown compression method '$comp'\n";
6302 }
7c536e11 6303 $add_pipe->($cmd);
91bd6c90
DM
6304 }
6305
6306 my $tmpdir = "/var/tmp/vzdumptmp$$";
6307 rmtree $tmpdir;
6308
6309 # disable interrupts (always do cleanups)
5b97ef24
TL
6310 local $SIG{INT} =
6311 local $SIG{TERM} =
6312 local $SIG{QUIT} =
6313 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
91bd6c90
DM
6314
6315 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6316 POSIX::mkfifo($mapfifo, 0600);
6317 my $fifofh;
6318
6319 my $openfifo = sub {
6320 open($fifofh, '>', $mapfifo) || die $!;
6321 };
6322
7c536e11 6323 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
91bd6c90
DM
6324
6325 my $oldtimeout;
6326 my $timeout = 5;
6327
6328 my $devinfo = {};
6329
6330 my $rpcenv = PVE::RPCEnvironment::get();
6331
ffda963f 6332 my $conffile = PVE::QemuConfig->config_file($vmid);
91bd6c90
DM
6333 my $tmpfn = "$conffile.$$.tmp";
6334
ed221350 6335 # Note: $oldconf is undef if VM does not exists
ffda963f
FG
6336 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6337 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
ed221350 6338
7c536e11
WB
6339 my %storage_limits;
6340
91bd6c90
DM
6341 my $print_devmap = sub {
6342 my $virtdev_hash = {};
6343
6344 my $cfgfn = "$tmpdir/qemu-server.conf";
6345
6346 # we can read the config - that is already extracted
6347 my $fh = IO::File->new($cfgfn, "r") ||
6348 "unable to read qemu-server.conf - $!\n";
6349
6738ab9c 6350 my $fwcfgfn = "$tmpdir/qemu-server.fw";
3457d090
WL
6351 if (-f $fwcfgfn) {
6352 my $pve_firewall_dir = '/etc/pve/firewall';
6353 mkdir $pve_firewall_dir; # make sure the dir exists
6354 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6355 }
6738ab9c 6356
91bd6c90
DM
6357 while (defined(my $line = <$fh>)) {
6358 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6359 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6360 die "archive does not contain data for drive '$virtdev'\n"
6361 if !$devinfo->{$devname};
6362 if (defined($opts->{storage})) {
6363 $storeid = $opts->{storage} || 'local';
6364 } elsif (!$storeid) {
6365 $storeid = 'local';
6366 }
6367 $format = 'raw' if !$format;
6368 $devinfo->{$devname}->{devname} = $devname;
6369 $devinfo->{$devname}->{virtdev} = $virtdev;
6370 $devinfo->{$devname}->{format} = $format;
6371 $devinfo->{$devname}->{storeid} = $storeid;
6372
be190583 6373 # check permission on storage
91bd6c90
DM
6374 my $pool = $opts->{pool}; # todo: do we need that?
6375 if ($user ne 'root@pam') {
6376 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6377 }
6378
7c536e11
WB
6379 $storage_limits{$storeid} = $bwlimit;
6380
91bd6c90 6381 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
c4ab3c55
ML
6382 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6383 my $virtdev = $1;
6384 my $drive = parse_drive($virtdev, $2);
6385 if (drive_is_cloudinit($drive)) {
6386 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
6387 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
6388 my $format = qemu_img_format($scfg, $volname); # has 'raw' fallback
6389
6390 my $d = {
6391 format => $format,
6392 storeid => $opts->{storage} // $storeid,
6393 size => PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE,
6394 file => $drive->{file}, # to make drive_is_cloudinit check possible
6395 name => "vm-$vmid-cloudinit",
87056e18 6396 is_cloudinit => 1,
c4ab3c55
ML
6397 };
6398 $virtdev_hash->{$virtdev} = $d;
6399 }
91bd6c90
DM
6400 }
6401 }
6402
7c536e11
WB
6403 foreach my $key (keys %storage_limits) {
6404 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$key], $bwlimit);
6405 next if !$limit;
6406 print STDERR "rate limit for storage $key: $limit KiB/s\n";
6407 $storage_limits{$key} = $limit * 1024;
6408 }
6409
91bd6c90 6410 foreach my $devname (keys %$devinfo) {
be190583
DM
6411 die "found no device mapping information for device '$devname'\n"
6412 if !$devinfo->{$devname}->{virtdev};
91bd6c90
DM
6413 }
6414
ed221350 6415 # create empty/temp config
be190583 6416 if ($oldconf) {
ed221350
DM
6417 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
6418 foreach_drive($oldconf, sub {
6419 my ($ds, $drive) = @_;
6420
a82348eb 6421 return if drive_is_cdrom($drive, 1);
ed221350
DM
6422
6423 my $volid = $drive->{file};
ed221350
DM
6424 return if !$volid || $volid =~ m|^/|;
6425
6426 my ($path, $owner) = PVE::Storage::path($cfg, $volid);
6427 return if !$path || !$owner || ($owner != $vmid);
6428
6429 # Note: only delete disk we want to restore
6430 # other volumes will become unused
6431 if ($virtdev_hash->{$ds}) {
6b72854b
FG
6432 eval { PVE::Storage::vdisk_free($cfg, $volid); };
6433 if (my $err = $@) {
6434 warn $err;
6435 }
ed221350
DM
6436 }
6437 });
381b8fae 6438
2b2923ae 6439 # delete vmstate files, after the restore we have no snapshots anymore
381b8fae
DC
6440 foreach my $snapname (keys %{$oldconf->{snapshots}}) {
6441 my $snap = $oldconf->{snapshots}->{$snapname};
6442 if ($snap->{vmstate}) {
6443 eval { PVE::Storage::vdisk_free($cfg, $snap->{vmstate}); };
6444 if (my $err = $@) {
6445 warn $err;
6446 }
6447 }
6448 }
ed221350
DM
6449 }
6450
6451 my $map = {};
91bd6c90
DM
6452 foreach my $virtdev (sort keys %$virtdev_hash) {
6453 my $d = $virtdev_hash->{$virtdev};
6454 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
7c536e11
WB
6455 my $storeid = $d->{storeid};
6456 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
6457
6458 my $map_opts = '';
6459 if (my $limit = $storage_limits{$storeid}) {
6460 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6461 }
8fd57431
DM
6462
6463 # test if requested format is supported
7c536e11 6464 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($cfg, $storeid);
8fd57431
DM
6465 my $supported = grep { $_ eq $d->{format} } @$validFormats;
6466 $d->{format} = $defFormat if !$supported;
6467
87056e18
TL
6468 my $name;
6469 if ($d->{is_cloudinit}) {
6470 $name = $d->{name};
6471 $name .= ".$d->{format}" if $d->{format} ne 'raw';
c4ab3c55 6472 }
2b2923ae
TL
6473
6474 my $volid = PVE::Storage::vdisk_alloc($cfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
91bd6c90
DM
6475 print STDERR "new volume ID is '$volid'\n";
6476 $d->{volid} = $volid;
91bd6c90 6477
2b2923ae 6478 PVE::Storage::activate_volumes($cfg, [$volid]);
5f96f4df 6479
91bd6c90 6480 my $write_zeros = 1;
88240a83 6481 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
91bd6c90
DM
6482 $write_zeros = 0;
6483 }
6484
87056e18
TL
6485 if (!$d->{is_cloudinit}) {
6486 my $path = PVE::Storage::path($cfg, $volid);
6487
c4ab3c55 6488 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
91bd6c90 6489
c4ab3c55
ML
6490 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6491 }
91bd6c90
DM
6492 $map->{$virtdev} = $volid;
6493 }
6494
6495 $fh->seek(0, 0) || die "seek failed - $!\n";
6496
6497 my $outfd = new IO::File ($tmpfn, "w") ||
6498 die "unable to write config for VM $vmid\n";
6499
6500 my $cookie = { netcount => 0 };
6501 while (defined(my $line = <$fh>)) {
be190583 6502 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
91bd6c90
DM
6503 }
6504
6505 $fh->close();
6506 $outfd->close();
6507 };
6508
6509 eval {
6510 # enable interrupts
6cb0144a
EK
6511 local $SIG{INT} =
6512 local $SIG{TERM} =
6513 local $SIG{QUIT} =
6514 local $SIG{HUP} =
6515 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
91bd6c90
DM
6516 local $SIG{ALRM} = sub { die "got timeout\n"; };
6517
6518 $oldtimeout = alarm($timeout);
6519
6520 my $parser = sub {
6521 my $line = shift;
6522
6523 print "$line\n";
6524
6525 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6526 my ($dev_id, $size, $devname) = ($1, $2, $3);
6527 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
6528 } elsif ($line =~ m/^CTIME: /) {
46f58b5f 6529 # we correctly received the vma config, so we can disable
3cf90d7a
DM
6530 # the timeout now for disk allocation (set to 10 minutes, so
6531 # that we always timeout if something goes wrong)
6532 alarm(600);
91bd6c90
DM
6533 &$print_devmap();
6534 print $fifofh "done\n";
6535 my $tmp = $oldtimeout || 0;
6536 $oldtimeout = undef;
6537 alarm($tmp);
6538 close($fifofh);
6539 }
6540 };
be190583 6541
7c536e11
WB
6542 print "restore vma archive: $dbg_cmdstring\n";
6543 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
91bd6c90
DM
6544 };
6545 my $err = $@;
6546
6547 alarm($oldtimeout) if $oldtimeout;
6548
5f96f4df
WL
6549 my $vollist = [];
6550 foreach my $devname (keys %$devinfo) {
6551 my $volid = $devinfo->{$devname}->{volid};
6552 push @$vollist, $volid if $volid;
6553 }
6554
5f96f4df
WL
6555 PVE::Storage::deactivate_volumes($cfg, $vollist);
6556
91bd6c90
DM
6557 unlink $mapfifo;
6558
6559 if ($err) {
6560 rmtree $tmpdir;
6561 unlink $tmpfn;
6562
91bd6c90
DM
6563 foreach my $devname (keys %$devinfo) {
6564 my $volid = $devinfo->{$devname}->{volid};
6565 next if !$volid;
6566 eval {
6567 if ($volid =~ m|^/|) {
6568 unlink $volid || die 'unlink failed\n';
6569 } else {
6570 PVE::Storage::vdisk_free($cfg, $volid);
6571 }
6572 print STDERR "temporary volume '$volid' sucessfuly removed\n";
6573 };
6574 print STDERR "unable to cleanup '$volid' - $@" if $@;
6575 }
6576 die $err;
6577 }
6578
6579 rmtree $tmpdir;
ed221350
DM
6580
6581 rename($tmpfn, $conffile) ||
91bd6c90
DM
6582 die "unable to commit configuration file '$conffile'\n";
6583
ed221350
DM
6584 PVE::Cluster::cfs_update(); # make sure we read new file
6585
91bd6c90
DM
6586 eval { rescan($vmid, 1); };
6587 warn $@ if $@;
6588}
6589
6590sub restore_tar_archive {
6591 my ($archive, $vmid, $user, $opts) = @_;
6592
9c502e26 6593 if ($archive ne '-') {
ed221350 6594 my $firstfile = tar_archive_read_firstfile($archive);
9c502e26
DM
6595 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6596 if $firstfile ne 'qemu-server.conf';
6597 }
3e16d5fc 6598
20519efc 6599 my $storecfg = PVE::Storage::config();
ebb55558 6600
4b026937
TL
6601 # avoid zombie disks when restoring over an existing VM -> cleanup first
6602 # pass keep_empty_config=1 to keep the config (thus VMID) reserved for us
6603 # skiplock=1 because qmrestore has set the 'create' lock itself already
ffda963f 6604 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
b04ea584 6605 destroy_vm($storecfg, $vmid, 1, { lock => 'restore' }) if -f $vmcfgfn;
ed221350 6606
3e16d5fc
DM
6607 my $tocmd = "/usr/lib/qemu-server/qmextract";
6608
2415a446 6609 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
a0d1b1a2 6610 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
3e16d5fc
DM
6611 $tocmd .= ' --prealloc' if $opts->{prealloc};
6612 $tocmd .= ' --info' if $opts->{info};
6613
a0d1b1a2 6614 # tar option "xf" does not autodetect compression when read from STDIN,
9c502e26 6615 # so we pipe to zcat
2415a446
DM
6616 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
6617 PVE::Tools::shellquote("--to-command=$tocmd");
3e16d5fc
DM
6618
6619 my $tmpdir = "/var/tmp/vzdumptmp$$";
6620 mkpath $tmpdir;
6621
6622 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
6623 local $ENV{VZDUMP_VMID} = $vmid;
a0d1b1a2 6624 local $ENV{VZDUMP_USER} = $user;
3e16d5fc 6625
ffda963f 6626 my $conffile = PVE::QemuConfig->config_file($vmid);
3e16d5fc
DM
6627 my $tmpfn = "$conffile.$$.tmp";
6628
6629 # disable interrupts (always do cleanups)
6cb0144a
EK
6630 local $SIG{INT} =
6631 local $SIG{TERM} =
6632 local $SIG{QUIT} =
6633 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
3e16d5fc 6634
afdb31d5 6635 eval {
3e16d5fc 6636 # enable interrupts
6cb0144a
EK
6637 local $SIG{INT} =
6638 local $SIG{TERM} =
6639 local $SIG{QUIT} =
6640 local $SIG{HUP} =
6641 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
3e16d5fc 6642
9c502e26
DM
6643 if ($archive eq '-') {
6644 print "extracting archive from STDIN\n";
6645 run_command($cmd, input => "<&STDIN");
6646 } else {
6647 print "extracting archive '$archive'\n";
6648 run_command($cmd);
6649 }
3e16d5fc
DM
6650
6651 return if $opts->{info};
6652
6653 # read new mapping
6654 my $map = {};
6655 my $statfile = "$tmpdir/qmrestore.stat";
6656 if (my $fd = IO::File->new($statfile, "r")) {
6657 while (defined (my $line = <$fd>)) {
6658 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6659 $map->{$1} = $2 if $1;
6660 } else {
6661 print STDERR "unable to parse line in statfile - $line\n";
6662 }
6663 }
6664 $fd->close();
6665 }
6666
6667 my $confsrc = "$tmpdir/qemu-server.conf";
6668
6669 my $srcfd = new IO::File($confsrc, "r") ||
6670 die "unable to open file '$confsrc'\n";
6671
6672 my $outfd = new IO::File ($tmpfn, "w") ||
6673 die "unable to write config for VM $vmid\n";
6674
91bd6c90 6675 my $cookie = { netcount => 0 };
3e16d5fc 6676 while (defined (my $line = <$srcfd>)) {
be190583 6677 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
3e16d5fc
DM
6678 }
6679
6680 $srcfd->close();
6681 $outfd->close();
6682 };
7dc7f315 6683 if (my $err = $@) {
3e16d5fc 6684 unlink $tmpfn;
ed221350 6685 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
3e16d5fc 6686 die $err;
afdb31d5 6687 }
3e16d5fc
DM
6688
6689 rmtree $tmpdir;
6690
6691 rename $tmpfn, $conffile ||
6692 die "unable to commit configuration file '$conffile'\n";
91bd6c90 6693
ed221350
DM
6694 PVE::Cluster::cfs_update(); # make sure we read new file
6695
91bd6c90
DM
6696 eval { rescan($vmid, 1); };
6697 warn $@ if $@;
3e16d5fc
DM
6698};
6699
65a5ce88 6700sub foreach_storage_used_by_vm {
18bfb361
DM
6701 my ($conf, $func) = @_;
6702
6703 my $sidhash = {};
6704
8ddbcf8b
FG
6705 foreach_drive($conf, sub {
6706 my ($ds, $drive) = @_;
6707 return if drive_is_cdrom($drive);
18bfb361
DM
6708
6709 my $volid = $drive->{file};
6710
6711 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
be190583 6712 $sidhash->{$sid} = $sid if $sid;
8ddbcf8b 6713 });
18bfb361
DM
6714
6715 foreach my $sid (sort keys %$sidhash) {
6716 &$func($sid);
6717 }
6718}
6719
e5eaa028
WL
6720sub do_snapshots_with_qemu {
6721 my ($storecfg, $volid) = @_;
6722
6723 my $storage_name = PVE::Storage::parse_volume_id($volid);
8aa2ed7c 6724 my $scfg = $storecfg->{ids}->{$storage_name};
e5eaa028 6725
8aa2ed7c 6726 if ($qemu_snap_storage->{$scfg->{type}} && !$scfg->{krbd}){
e5eaa028
WL
6727 return 1;
6728 }
6729
6730 if ($volid =~ m/\.(qcow2|qed)$/){
6731 return 1;
6732 }
6733
6734 return undef;
6735}
6736
4dcc780c 6737sub qga_check_running {
a4938c72 6738 my ($vmid, $nowarn) = @_;
4dcc780c
WL
6739
6740 eval { vm_mon_cmd($vmid, "guest-ping", timeout => 3); };
6741 if ($@) {
a4938c72 6742 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
4dcc780c
WL
6743 return 0;
6744 }
6745 return 1;
6746}
6747
04a69bb4
AD
6748sub template_create {
6749 my ($vmid, $conf, $disk) = @_;
6750
04a69bb4 6751 my $storecfg = PVE::Storage::config();
04a69bb4 6752
9cd07842
DM
6753 foreach_drive($conf, sub {
6754 my ($ds, $drive) = @_;
6755
6756 return if drive_is_cdrom($drive);
6757 return if $disk && $ds ne $disk;
6758
6759 my $volid = $drive->{file};
bbd56097 6760 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
9cd07842 6761
04a69bb4
AD
6762 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
6763 $drive->{file} = $voliddst;
152fe752 6764 $conf->{$ds} = print_drive($vmid, $drive);
ffda963f 6765 PVE::QemuConfig->write_config($vmid, $conf);
04a69bb4 6766 });
04a69bb4
AD
6767}
6768
92bdc3f0
DC
6769sub convert_iscsi_path {
6770 my ($path) = @_;
6771
6772 if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
6773 my $portal = $1;
6774 my $target = $2;
6775 my $lun = $3;
6776
6777 my $initiator_name = get_initiator_name();
6778
6779 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6780 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6781 }
6782
6783 die "cannot convert iscsi path '$path', unkown format\n";
6784}
6785
5133de42 6786sub qemu_img_convert {
988e2714 6787 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5133de42
AD
6788
6789 my $storecfg = PVE::Storage::config();
6790 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
6791 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
6792
af1f1ec0 6793 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6bb91c17 6794
af1f1ec0
DC
6795 my $cachemode;
6796 my $src_path;
6797 my $src_is_iscsi = 0;
6798 my $src_format = 'raw';
6bb91c17 6799
af1f1ec0
DC
6800 if ($src_storeid) {
6801 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
5133de42 6802 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
af1f1ec0
DC
6803 $src_format = qemu_img_format($src_scfg, $src_volname);
6804 $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
6805 $src_is_iscsi = ($src_path =~ m|^iscsi://|);
6806 $cachemode = 'none' if $src_scfg->{type} eq 'zfspool';
6807 } elsif (-f $src_volid) {
6808 $src_path = $src_volid;
6809 if ($src_path =~ m/\.($QEMU_FORMAT_RE)$/) {
6810 $src_format = $1;
6811 }
6812 }
5133de42 6813
af1f1ec0 6814 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
5133de42 6815
af1f1ec0
DC
6816 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
6817 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
6818 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
6819 my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
5133de42 6820
af1f1ec0
DC
6821 my $cmd = [];
6822 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6823 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6824 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
6825 push @$cmd, '-T', $cachemode if defined($cachemode);
6826
6827 if ($src_is_iscsi) {
6828 push @$cmd, '--image-opts';
6829 $src_path = convert_iscsi_path($src_path);
6830 } else {
6831 push @$cmd, '-f', $src_format;
6832 }
92bdc3f0 6833
af1f1ec0
DC
6834 if ($dst_is_iscsi) {
6835 push @$cmd, '--target-image-opts';
6836 $dst_path = convert_iscsi_path($dst_path);
6837 } else {
6838 push @$cmd, '-O', $dst_format;
6839 }
92bdc3f0 6840
af1f1ec0 6841 push @$cmd, $src_path;
92bdc3f0 6842
af1f1ec0
DC
6843 if (!$dst_is_iscsi && $is_zero_initialized) {
6844 push @$cmd, "zeroinit:$dst_path";
6845 } else {
6846 push @$cmd, $dst_path;
6847 }
92bdc3f0 6848
af1f1ec0
DC
6849 my $parser = sub {
6850 my $line = shift;
6851 if($line =~ m/\((\S+)\/100\%\)/){
6852 my $percent = $1;
6853 my $transferred = int($size * $percent / 100);
6854 my $remaining = $size - $transferred;
92bdc3f0 6855
af1f1ec0 6856 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
988e2714 6857 }
5133de42 6858
af1f1ec0 6859 };
5133de42 6860
af1f1ec0
DC
6861 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
6862 my $err = $@;
6863 die "copy failed: $err" if $err;
5133de42
AD
6864}
6865
6866sub qemu_img_format {
6867 my ($scfg, $volname) = @_;
6868
9c52f5ed 6869 if ($scfg->{path} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
5133de42 6870 return $1;
be190583 6871 } else {
5133de42 6872 return "raw";
5133de42
AD
6873 }
6874}
6875
cfad42af 6876sub qemu_drive_mirror {
9fa05d31 6877 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
cfad42af 6878
5a345967
AD
6879 $jobs = {} if !$jobs;
6880
6881 my $qemu_target;
6882 my $format;
35e4ab04 6883 $jobs->{"drive-$drive"} = {};
152fe752 6884
1e5143de 6885 if ($dst_volid =~ /^nbd:/) {
87955688 6886 $qemu_target = $dst_volid;
5a345967 6887 $format = "nbd";
5a345967 6888 } else {
5a345967
AD
6889 my $storecfg = PVE::Storage::config();
6890 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
6891
6892 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
cfad42af 6893
5a345967 6894 $format = qemu_img_format($dst_scfg, $dst_volname);
21ccdb50 6895
5a345967 6896 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
21ccdb50 6897
5a345967
AD
6898 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
6899 }
988e2714
WB
6900
6901 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
88383920
DM
6902 $opts->{format} = $format if $format;
6903
9fa05d31 6904 if (defined($bwlimit)) {
f6409f61
TL
6905 $opts->{speed} = $bwlimit * 1024;
6906 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
9fa05d31
SI
6907 } else {
6908 print "drive mirror is starting for drive-$drive\n";
6909 }
21ccdb50 6910
6dde5ea2
TL
6911 # if a job already runs for this device we get an error, catch it for cleanup
6912 eval { vm_mon_cmd($vmid, "drive-mirror", %$opts); };
5a345967
AD
6913 if (my $err = $@) {
6914 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6dde5ea2
TL
6915 warn "$@\n" if $@;
6916 die "mirroring error: $err\n";
5a345967
AD
6917 }
6918
5619e74a 6919 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
5a345967
AD
6920}
6921
6922sub qemu_drive_mirror_monitor {
5619e74a 6923 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
2e953867 6924
08ac653f 6925 eval {
5a345967
AD
6926 my $err_complete = 0;
6927
08ac653f 6928 while (1) {
5a345967
AD
6929 die "storage migration timed out\n" if $err_complete > 300;
6930
08ac653f 6931 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
08ac653f 6932
5a345967
AD
6933 my $running_mirror_jobs = {};
6934 foreach my $stat (@$stats) {
6935 next if $stat->{type} ne 'mirror';
6936 $running_mirror_jobs->{$stat->{device}} = $stat;
6937 }
08ac653f 6938
5a345967 6939 my $readycounter = 0;
67fb9de6 6940
5a345967
AD
6941 foreach my $job (keys %$jobs) {
6942
6943 if(defined($jobs->{$job}->{complete}) && !defined($running_mirror_jobs->{$job})) {
6944 print "$job : finished\n";
6945 delete $jobs->{$job};
6946 next;
6947 }
6948
bd2d5fe6 6949 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
f34ebd52 6950
5a345967
AD
6951 my $busy = $running_mirror_jobs->{$job}->{busy};
6952 my $ready = $running_mirror_jobs->{$job}->{ready};
6953 if (my $total = $running_mirror_jobs->{$job}->{len}) {
6954 my $transferred = $running_mirror_jobs->{$job}->{offset} || 0;
6955 my $remaining = $total - $transferred;
6956 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
08ac653f 6957
5a345967
AD
6958 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6959 }
f34ebd52 6960
d1782eba 6961 $readycounter++ if $running_mirror_jobs->{$job}->{ready};
5a345967 6962 }
b467f79a 6963
5a345967
AD
6964 last if scalar(keys %$jobs) == 0;
6965
6966 if ($readycounter == scalar(keys %$jobs)) {
6967 print "all mirroring jobs are ready \n";
6968 last if $skipcomplete; #do the complete later
6969
6970 if ($vmiddst && $vmiddst != $vmid) {
1a988fd2
DC
6971 my $agent_running = $qga && qga_check_running($vmid);
6972 if ($agent_running) {
5619e74a
AD
6973 print "freeze filesystem\n";
6974 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-freeze"); };
6975 } else {
6976 print "suspend vm\n";
6977 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
6978 }
6979
5a345967
AD
6980 # if we clone a disk for a new target vm, we don't switch the disk
6981 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
5619e74a 6982
1a988fd2 6983 if ($agent_running) {
5619e74a
AD
6984 print "unfreeze filesystem\n";
6985 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-thaw"); };
6986 } else {
6987 print "resume vm\n";
6988 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
6989 }
6990
2e953867 6991 last;
5a345967
AD
6992 } else {
6993
6994 foreach my $job (keys %$jobs) {
6995 # try to switch the disk if source and destination are on the same guest
bd2d5fe6 6996 print "$job: Completing block job...\n";
5a345967
AD
6997
6998 eval { vm_mon_cmd($vmid, "block-job-complete", device => $job) };
6999 if ($@ =~ m/cannot be completed/) {
bd2d5fe6 7000 print "$job: Block job cannot be completed, try again.\n";
5a345967
AD
7001 $err_complete++;
7002 }else {
bd2d5fe6 7003 print "$job: Completed successfully.\n";
5a345967
AD
7004 $jobs->{$job}->{complete} = 1;
7005 }
7006 }
2e953867 7007 }
08ac653f 7008 }
08ac653f 7009 sleep 1;
cfad42af 7010 }
08ac653f 7011 };
88383920 7012 my $err = $@;
08ac653f 7013
88383920 7014 if ($err) {
5a345967 7015 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
88383920
DM
7016 die "mirroring error: $err";
7017 }
7018
5a345967
AD
7019}
7020
7021sub qemu_blockjobs_cancel {
7022 my ($vmid, $jobs) = @_;
7023
7024 foreach my $job (keys %$jobs) {
bd2d5fe6 7025 print "$job: Cancelling block job\n";
5a345967
AD
7026 eval { vm_mon_cmd($vmid, "block-job-cancel", device => $job); };
7027 $jobs->{$job}->{cancel} = 1;
7028 }
7029
7030 while (1) {
7031 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
7032
7033 my $running_jobs = {};
7034 foreach my $stat (@$stats) {
7035 $running_jobs->{$stat->{device}} = $stat;
7036 }
7037
7038 foreach my $job (keys %$jobs) {
7039
bd2d5fe6
WB
7040 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
7041 print "$job: Done.\n";
5a345967
AD
7042 delete $jobs->{$job};
7043 }
7044 }
7045
7046 last if scalar(keys %$jobs) == 0;
7047
7048 sleep 1;
cfad42af
AD
7049 }
7050}
7051
152fe752 7052sub clone_disk {
be190583 7053 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
7e303ef3 7054 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
152fe752
DM
7055
7056 my $newvolid;
7057
7058 if (!$full) {
7059 print "create linked clone of drive $drivename ($drive->{file})\n";
258e646c 7060 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
152fe752
DM
7061 push @$newvollist, $newvolid;
7062 } else {
5a345967 7063
152fe752
DM
7064 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
7065 $storeid = $storage if $storage;
7066
44549149 7067 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
152fe752
DM
7068 my ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 3);
7069
7070 print "create full clone of drive $drivename ($drive->{file})\n";
931432bd 7071 my $name = undef;
931432bd 7072 $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
152fe752
DM
7073 push @$newvollist, $newvolid;
7074
3999f370 7075 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
1dbd6d30 7076
988e2714 7077 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
152fe752 7078 if (!$running || $snapname) {
d189e590 7079 # TODO: handle bwlimits
988e2714 7080 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
152fe752 7081 } else {
2e541679
AD
7082
7083 my $kvmver = get_running_qemu_version ($vmid);
7084 if (!qemu_machine_feature_enabled (undef, $kvmver, 2, 7)) {
961af8a3
WB
7085 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7086 if $drive->{iothread};
2e541679 7087 }
2af848a2 7088
7e303ef3 7089 qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga, $bwlimit);
be190583 7090 }
152fe752
DM
7091 }
7092
7093 my ($size) = PVE::Storage::volume_size_info($storecfg, $newvolid, 3);
7094
7095 my $disk = $drive;
7096 $disk->{format} = undef;
7097 $disk->{file} = $newvolid;
7098 $disk->{size} = $size;
7099
7100 return $disk;
7101}
7102
ff556cf2
DM
7103# this only works if VM is running
7104sub get_current_qemu_machine {
7105 my ($vmid) = @_;
7106
7107 my $cmd = { execute => 'query-machines', arguments => {} };
8e90138a 7108 my $res = vm_qmp_command($vmid, $cmd);
ff556cf2
DM
7109
7110 my ($current, $default);
7111 foreach my $e (@$res) {
7112 $default = $e->{name} if $e->{'is-default'};
7113 $current = $e->{name} if $e->{'is-current'};
7114 }
7115
7116 # fallback to the default machine if current is not supported by qemu
7117 return $current || $default || 'pc';
7118}
7119
98cfd8b6
AD
7120sub get_running_qemu_version {
7121 my ($vmid) = @_;
7122 my $cmd = { execute => 'query-version', arguments => {} };
7123 my $res = vm_qmp_command($vmid, $cmd);
7124 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7125}
7126
23f73120
AD
7127sub qemu_machine_feature_enabled {
7128 my ($machine, $kvmver, $version_major, $version_minor) = @_;
7129
7130 my $current_major;
7131 my $current_minor;
7132
d731ecbe 7133 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
23f73120
AD
7134
7135 $current_major = $3;
7136 $current_minor = $4;
7137
7138 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
7139
7140 $current_major = $1;
7141 $current_minor = $2;
7142 }
7143
19e9b308
TL
7144 return 1 if version_cmp($current_major, $version_major, $current_minor, $version_minor) >= 0;
7145}
7146
7147# gets in pairs the versions you want to compares, i.e.:
7148# ($a-major, $b-major, $a-minor, $b-minor, $a-extra, $b-extra, ...)
7149# returns 0 if same, -1 if $a is older than $b, +1 if $a is newer than $b
7150sub version_cmp {
7151 my @versions = @_;
7152
7153 my $size = scalar(@versions);
7154
7155 return 0 if $size == 0;
7156 die "cannot compare odd count of versions" if $size & 1;
7157
7158 for (my $i = 0; $i < $size; $i += 2) {
7159 my ($a, $b) = splice(@versions, 0, 2);
7160 $a //= 0;
7161 $b //= 0;
7162
7163 return 1 if $a > $b;
7164 return -1 if $a < $b;
7165 }
7166 return 0;
23f73120
AD
7167}
7168
0600c3bf
TL
7169# dies if a) VM not running or not exisiting b) Version query failed
7170# So, any defined return value is valid, any invalid state can be caught by eval
48343b3f
TL
7171sub runs_at_least_qemu_version {
7172 my ($vmid, $major, $minor, $extra) = @_;
7173
0600c3bf
TL
7174 my $v = vm_qmp_command($vmid, { execute => 'query-version' });
7175 die "could not query currently running version for VM $vmid\n" if !defined($v);
48343b3f
TL
7176 $v = $v->{qemu};
7177
7178 return version_cmp($v->{major}, $major, $v->{minor}, $minor, $v->{micro}, $extra) >= 0;
7179}
7180
42dbd2ee 7181sub qemu_machine_pxe {
8071149b 7182 my ($vmid, $conf) = @_;
42dbd2ee 7183
8071149b 7184 my $machine = PVE::QemuServer::get_current_qemu_machine($vmid);
42dbd2ee 7185
3807f3e4
DC
7186 if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
7187 $machine .= '.pxe';
42dbd2ee
AD
7188 }
7189
d1363934 7190 return $machine;
42dbd2ee
AD
7191}
7192
249c4a6c
AD
7193sub qemu_use_old_bios_files {
7194 my ($machine_type) = @_;
7195
7196 return if !$machine_type;
7197
7198 my $use_old_bios_files = undef;
7199
7200 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7201 $machine_type = $1;
7202 $use_old_bios_files = 1;
7203 } else {
74cc511f 7204 my $kvmver = kvm_user_version();
249c4a6c
AD
7205 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7206 # load new efi bios files on migration. So this hack is required to allow
7207 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7208 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
74cc511f 7209 $use_old_bios_files = !qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 4);
249c4a6c
AD
7210 }
7211
7212 return ($use_old_bios_files, $machine_type);
7213}
7214
96ed3574
WB
7215sub create_efidisk($$$$$) {
7216 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
3e1f1122 7217
96ed3574
WB
7218 my (undef, $ovmf_vars) = get_ovmf_files($arch);
7219 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
3e1f1122 7220
af1f1ec0
DC
7221 my $vars_size_b = -s $ovmf_vars;
7222 my $vars_size = PVE::Tools::convert_size($vars_size_b, 'b' => 'kb');
3e1f1122
TL
7223 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7224 PVE::Storage::activate_volumes($storecfg, [$volid]);
7225
af1f1ec0 7226 qemu_img_convert($ovmf_vars, $volid, $vars_size_b, undef, 0);
3e1f1122
TL
7227
7228 return ($volid, $vars_size);
7229}
7230
22de899a
AD
7231sub vm_iothreads_list {
7232 my ($vmid) = @_;
7233
7234 my $res = vm_mon_cmd($vmid, 'query-iothreads');
7235
7236 my $iothreads = {};
7237 foreach my $iothread (@$res) {
7238 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
7239 }
7240
7241 return $iothreads;
7242}
7243
ee034f5c
AD
7244sub scsihw_infos {
7245 my ($conf, $drive) = @_;
7246
7247 my $maxdev = 0;
7248
7fe1b688 7249 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
ee034f5c 7250 $maxdev = 7;
a1511b3c 7251 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
ee034f5c
AD
7252 $maxdev = 1;
7253 } else {
7254 $maxdev = 256;
7255 }
7256
7257 my $controller = int($drive->{index} / $maxdev);
a1511b3c 7258 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') ? "virtioscsi" : "scsihw";
ee034f5c
AD
7259
7260 return ($maxdev, $controller, $controller_prefix);
7261}
a1511b3c 7262
075e8249 7263sub add_hyperv_enlightenments {
2894c247 7264 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
4317f69f 7265
4317f69f
AD
7266 return if $winversion < 6;
7267 return if $bios && $bios eq 'ovmf' && $winversion < 8;
7268
2894c247
DC
7269 if ($gpu_passthrough || defined($hv_vendor_id)) {
7270 $hv_vendor_id //= 'proxmox';
7271 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
7272 }
5aba3953 7273
4317f69f
AD
7274 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
7275 push @$cpuFlags , 'hv_spinlocks=0x1fff';
7276 push @$cpuFlags , 'hv_vapic';
7277 push @$cpuFlags , 'hv_time';
7278 } else {
7279 push @$cpuFlags , 'hv_spinlocks=0xffff';
7280 }
7281
7282 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 6)) {
7283 push @$cpuFlags , 'hv_reset';
7284 push @$cpuFlags , 'hv_vpindex';
7285 push @$cpuFlags , 'hv_runtime';
7286 }
7287
7288 if ($winversion >= 7) {
7289 push @$cpuFlags , 'hv_relaxed';
ebb346d6 7290
df648a6a 7291 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 12)) {
ebb346d6
AD
7292 push @$cpuFlags , 'hv_synic';
7293 push @$cpuFlags , 'hv_stimer';
7294 }
392dfbf5 7295
392dfbf5
SR
7296 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 3, 1)) {
7297 push @$cpuFlags , 'hv_ipi';
392dfbf5 7298 }
4317f69f
AD
7299 }
7300}
7301
7302sub windows_version {
7303 my ($ostype) = @_;
7304
7305 return 0 if !$ostype;
7306
7307 my $winversion = 0;
7308
7309 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7310 $winversion = 5;
7311 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7312 $winversion = 6;
7313 } elsif ($ostype =~ m/^win(\d+)$/) {
7314 $winversion = $1;
7315 }
7316
7317 return $winversion;
7318}
7319
44549149
EK
7320sub resolve_dst_disk_format {
7321 my ($storecfg, $storeid, $src_volname, $format) = @_;
7322 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
7323
7324 if (!$format) {
7325 # if no target format is specified, use the source disk format as hint
7326 if ($src_volname) {
7327 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7328 $format = qemu_img_format($scfg, $src_volname);
7329 } else {
7330 return $defFormat;
7331 }
7332 }
7333
7334 # test if requested format is supported - else use default
7335 my $supported = grep { $_ eq $format } @$validFormats;
7336 $format = $defFormat if !$supported;
7337 return $format;
7338}
7339
ae2fcb3b
EK
7340sub resolve_first_disk {
7341 my $conf = shift;
7342 my @disks = PVE::QemuServer::valid_drive_names();
7343 my $firstdisk;
7344 foreach my $ds (reverse @disks) {
7345 next if !$conf->{$ds};
7346 my $disk = PVE::QemuServer::parse_drive($ds, $conf->{$ds});
7347 next if PVE::QemuServer::drive_is_cdrom($disk);
7348 $firstdisk = $ds;
7349 }
7350 return $firstdisk;
7351}
7352
6ee499ff 7353sub generate_uuid {
ae2fcb3b
EK
7354 my ($uuid, $uuid_str);
7355 UUID::generate($uuid);
7356 UUID::unparse($uuid, $uuid_str);
6ee499ff
DC
7357 return $uuid_str;
7358}
7359
7360sub generate_smbios1_uuid {
7361 return "uuid=".generate_uuid();
ae2fcb3b
EK
7362}
7363
9c152e87
TL
7364sub nbd_stop {
7365 my ($vmid) = @_;
7366
7367 vm_mon_cmd($vmid, 'nbd-server-stop');
7368}
7369
dae98db9
DC
7370sub create_reboot_request {
7371 my ($vmid) = @_;
7372 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7373 or die "failed to create reboot trigger file: $!\n";
7374 close($fh);
7375}
7376
7377sub clear_reboot_request {
7378 my ($vmid) = @_;
7379 my $path = "/run/qemu-server/$vmid.reboot";
7380 my $res = 0;
7381
7382 $res = unlink($path);
7383 die "could not remove reboot request for $vmid: $!"
7384 if !$res && $! != POSIX::ENOENT;
7385
7386 return $res;
7387}
7388
65e866e5
DM
7389# bash completion helper
7390
7391sub complete_backup_archives {
7392 my ($cmdname, $pname, $cvalue) = @_;
7393
7394 my $cfg = PVE::Storage::config();
7395
7396 my $storeid;
7397
7398 if ($cvalue =~ m/^([^:]+):/) {
7399 $storeid = $1;
7400 }
7401
7402 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
7403
7404 my $res = [];
7405 foreach my $id (keys %$data) {
7406 foreach my $item (@{$data->{$id}}) {
7407 next if $item->{format} !~ m/^vma\.(gz|lzo)$/;
7408 push @$res, $item->{volid} if defined($item->{volid});
7409 }
7410 }
7411
7412 return $res;
7413}
7414
7415my $complete_vmid_full = sub {
7416 my ($running) = @_;
7417
7418 my $idlist = vmstatus();
7419
7420 my $res = [];
7421
7422 foreach my $id (keys %$idlist) {
7423 my $d = $idlist->{$id};
7424 if (defined($running)) {
7425 next if $d->{template};
7426 next if $running && $d->{status} ne 'running';
7427 next if !$running && $d->{status} eq 'running';
7428 }
7429 push @$res, $id;
7430
7431 }
7432 return $res;
7433};
7434
7435sub complete_vmid {
7436 return &$complete_vmid_full();
7437}
7438
7439sub complete_vmid_stopped {
7440 return &$complete_vmid_full(0);
7441}
7442
7443sub complete_vmid_running {
7444 return &$complete_vmid_full(1);
7445}
7446
335af808
DM
7447sub complete_storage {
7448
7449 my $cfg = PVE::Storage::config();
7450 my $ids = $cfg->{ids};
7451
7452 my $res = [];
7453 foreach my $sid (keys %$ids) {
7454 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
c4c844ef 7455 next if !$ids->{$sid}->{content}->{images};
335af808
DM
7456 push @$res, $sid;
7457 }
7458
7459 return $res;
7460}
7461
1e3baf05 74621;