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