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