]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
fix #2408, #2355, #2380: use scsi-hd backend for iSCSI as well
[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
d1cbb1a9
SR
1901 if($path =~ m/^iscsi\:\/\// &&
1902 !qemu_machine_feature_enabled($machine_type, undef, 4, 1)) {
69bcf246
WB
1903 $devicetype = 'generic';
1904 }
1905 }
1906
1907 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)){
1908 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1909 } else {
1910 $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}";
1911 }
cdd20088 1912
6c875f9f
NC
1913 if ($drive->{ssd} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1914 $device .= ",rotation_rate=1";
1915 }
e741c516 1916 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
6c875f9f
NC
1917
1918 } elsif ($drive->{interface} eq 'ide' || $drive->{interface} eq 'sata') {
1919 my $maxdev = ($drive->{interface} eq 'sata') ? $MAX_SATA_DISKS : 2;
2ed36a41
DM
1920 my $controller = int($drive->{index} / $maxdev);
1921 my $unit = $drive->{index} % $maxdev;
1922 my $devicetype = ($drive->{media} && $drive->{media} eq 'cdrom') ? "cd" : "hd";
1923
6c875f9f
NC
1924 $device = "ide-$devicetype";
1925 if ($drive->{interface} eq 'ide') {
1926 $device .= ",bus=ide.$controller,unit=$unit";
1927 } else {
1928 $device .= ",bus=ahci$controller.$unit";
1929 }
1930 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1931
1932 if ($devicetype eq 'hd') {
1933 if (my $model = $drive->{model}) {
1934 $model = URI::Escape::uri_unescape($model);
1935 $device .= ",model=$model";
1936 }
1937 if ($drive->{ssd}) {
1938 $device .= ",rotation_rate=1";
1939 }
0f2812c2 1940 }
e741c516 1941 $device .= ",wwn=$drive->{wwn}" if $drive->{wwn};
2ed36a41
DM
1942 } elsif ($drive->{interface} eq 'usb') {
1943 die "implement me";
1944 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1945 } else {
1946 die "unsupported interface type";
ca916ecc
DA
1947 }
1948
3b408e82
DM
1949 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex};
1950
a70e7e6c
TL
1951 if (my $serial = $drive->{serial}) {
1952 $serial = URI::Escape::uri_unescape($serial);
1953 $device .= ",serial=$serial";
1954 }
1955
1956
ca916ecc
DA
1957 return $device;
1958}
1959
15b21acc 1960sub get_initiator_name {
46f58b5f 1961 my $initiator;
15b21acc 1962
46f58b5f
DM
1963 my $fh = IO::File->new('/etc/iscsi/initiatorname.iscsi') || return undef;
1964 while (defined(my $line = <$fh>)) {
1965 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
15b21acc
MR
1966 $initiator = $1;
1967 last;
1968 }
46f58b5f
DM
1969 $fh->close();
1970
15b21acc
MR
1971 return $initiator;
1972}
1973
1e3baf05
DM
1974sub print_drive_full {
1975 my ($storecfg, $vmid, $drive) = @_;
1976
d81f0f09
DM
1977 my $path;
1978 my $volid = $drive->{file};
1979 my $format;
370b05e7 1980
d81f0f09
DM
1981 if (drive_is_cdrom($drive)) {
1982 $path = get_iso_path($storecfg, $vmid, $volid);
1983 } else {
1984 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
1985 if ($storeid) {
1986 $path = PVE::Storage::path($storecfg, $volid);
1987 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
1988 $format = qemu_img_format($scfg, $volname);
1989 } else {
1990 $path = $volid;
5b61bff2 1991 $format = "raw";
d81f0f09
DM
1992 }
1993 }
1994
1e3baf05 1995 my $opts = '';
8a267708 1996 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1e3baf05 1997 foreach my $o (@qemu_drive_options) {
5fc74861 1998 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
19672434 1999 }
8a267708
DC
2000
2001 # snapshot only accepts on|off
2002 if (defined($drive->{snapshot})) {
2003 my $v = $drive->{snapshot} ? 'on' : 'off';
2004 $opts .= ",snapshot=$v";
2005 }
2006
fb8e95a2
WB
2007 foreach my $type (['', '-total'], [_rd => '-read'], [_wr => '-write']) {
2008 my ($dir, $qmpname) = @$type;
2009 if (my $v = $drive->{"mbps$dir"}) {
2010 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
2011 }
2012 if (my $v = $drive->{"mbps${dir}_max"}) {
2013 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
2014 }
2015 if (my $v = $drive->{"bps${dir}_max_length"}) {
2016 $opts .= ",throttling.bps$qmpname-max-length=$v";
2017 }
2018 if (my $v = $drive->{"iops${dir}"}) {
2019 $opts .= ",throttling.iops$qmpname=$v";
2020 }
2021 if (my $v = $drive->{"iops${dir}_max"}) {
8aca1654 2022 $opts .= ",throttling.iops$qmpname-max=$v";
fb8e95a2
WB
2023 }
2024 if (my $v = $drive->{"iops${dir}_max_length"}) {
8aca1654 2025 $opts .= ",throttling.iops$qmpname-max-length=$v";
fb8e95a2
WB
2026 }
2027 }
2028
d81f0f09
DM
2029 $opts .= ",format=$format" if $format && !$drive->{format};
2030
b2ee900e
WB
2031 my $cache_direct = 0;
2032
2033 if (my $cache = $drive->{cache}) {
2034 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
2035 } elsif (!drive_is_cdrom($drive)) {
2036 $opts .= ",cache=none";
2037 $cache_direct = 1;
2038 }
2039
2040 # aio native works only with O_DIRECT
2041 if (!$drive->{aio}) {
2042 if($cache_direct) {
2043 $opts .= ",aio=native";
2044 } else {
2045 $opts .= ",aio=threads";
2046 }
2047 }
11490cf2 2048
6e47c3b4
WB
2049 if (!drive_is_cdrom($drive)) {
2050 my $detectzeroes;
7d4e30f3 2051 if (defined($drive->{detect_zeroes}) && !$drive->{detect_zeroes}) {
6e47c3b4
WB
2052 $detectzeroes = 'off';
2053 } elsif ($drive->{discard}) {
2054 $detectzeroes = $drive->{discard} eq 'on' ? 'unmap' : 'on';
2055 } else {
2056 # This used to be our default with discard not being specified:
2057 $detectzeroes = 'on';
2058 }
2059 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
2060 }
f1e05305 2061
1e3baf05
DM
2062 my $pathinfo = $path ? "file=$path," : '';
2063
3ebfcc86 2064 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1e3baf05
DM
2065}
2066
cc4d6182 2067sub print_netdevice_full {
d559309f 2068 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
cc4d6182
DA
2069
2070 my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
2071
2072 my $device = $net->{model};
2073 if ($net->{model} eq 'virtio') {
2074 $device = 'virtio-net-pci';
2075 };
2076
d559309f 2077 my $pciaddr = print_pci_addr("$netid", $bridges, $arch, $machine_type);
5e2068d2 2078 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
a9410357
AD
2079 if ($net->{queues} && $net->{queues} > 1 && $net->{model} eq 'virtio'){
2080 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
2081 my $vectors = $net->{queues} * 2 + 2;
2082 $tmpstr .= ",vectors=$vectors,mq=on";
2083 }
cc4d6182 2084 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex} ;
ba9e1000
DM
2085
2086 if ($use_old_bios_files) {
2087 my $romfile;
2088 if ($device eq 'virtio-net-pci') {
2089 $romfile = 'pxe-virtio.rom';
2090 } elsif ($device eq 'e1000') {
2091 $romfile = 'pxe-e1000.rom';
2092 } elsif ($device eq 'ne2k') {
2093 $romfile = 'pxe-ne2k_pci.rom';
2094 } elsif ($device eq 'pcnet') {
2095 $romfile = 'pxe-pcnet.rom';
2096 } elsif ($device eq 'rtl8139') {
2097 $romfile = 'pxe-rtl8139.rom';
2098 }
2099 $tmpstr .= ",romfile=$romfile" if $romfile;
2100 }
2101
cc4d6182
DA
2102 return $tmpstr;
2103}
2104
2105sub print_netdev_full {
d559309f 2106 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
cc4d6182
DA
2107
2108 my $i = '';
2109 if ($netid =~ m/^net(\d+)$/) {
2110 $i = int($1);
2111 }
2112
2113 die "got strange net id '$i'\n" if $i >= ${MAX_NETS};
2114
2115 my $ifname = "tap${vmid}i$i";
2116
2117 # kvm uses TUNSETIFF ioctl, and that limits ifname length
2118 die "interface name '$ifname' is too long (max 15 character)\n"
2119 if length($ifname) >= 16;
2120
2121 my $vhostparam = '';
6f0cb675 2122 if (is_native($arch)) {
db70021b 2123 $vhostparam = ',vhost=on' if kernel_has_vhost_net() && $net->{model} eq 'virtio';
6f0cb675 2124 }
cc4d6182
DA
2125
2126 my $vmname = $conf->{name} || "vm$vmid";
2127
a9410357 2128 my $netdev = "";
208ba94e 2129 my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
a9410357 2130
cc4d6182 2131 if ($net->{bridge}) {
208ba94e 2132 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
cc4d6182 2133 } else {
a9410357 2134 $netdev = "type=user,id=$netid,hostname=$vmname";
cc4d6182 2135 }
a9410357
AD
2136
2137 $netdev .= ",queues=$net->{queues}" if ($net->{queues} && $net->{model} eq 'virtio');
2138
2139 return $netdev;
cc4d6182 2140}
1e3baf05 2141
0efb537e
AD
2142
2143sub print_cpu_device {
2144 my ($conf, $id) = @_;
2145
74c02ef7
PA
2146 my $kvm = $conf->{kvm} // 1;
2147 my $cpu = $kvm ? "kvm64" : "qemu64";
0efb537e
AD
2148 if (my $cputype = $conf->{cpu}) {
2149 my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
2150 or die "Cannot parse cpu description: $cputype\n";
2151 $cpu = $cpuconf->{cputype};
2152 }
2153
0efb537e
AD
2154 my $cores = $conf->{cores} || 1;
2155
2156 my $current_core = ($id - 1) % $cores;
7032e08c 2157 my $current_socket = int(($id - 1 - $current_core)/$cores);
0efb537e
AD
2158
2159 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2160}
2161
55655ebc
DC
2162my $vga_map = {
2163 'cirrus' => 'cirrus-vga',
2164 'std' => 'VGA',
2165 'vmware' => 'vmware-svga',
2166 'virtio' => 'virtio-vga',
2167};
2168
2169sub print_vga_device {
d559309f 2170 my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
55655ebc
DC
2171
2172 my $type = $vga_map->{$vga->{type}};
86c9fafe 2173 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
d559309f
WB
2174 $type = 'virtio-gpu';
2175 }
55655ebc
DC
2176 my $vgamem_mb = $vga->{memory};
2177 if ($qxlnum) {
2178 $type = $id ? 'qxl' : 'qxl-vga';
2179 }
2180 die "no devicetype for $vga->{type}\n" if !$type;
2181
2182 my $memory = "";
2183 if ($vgamem_mb) {
2184 if ($vga->{type} eq 'virtio') {
2185 my $bytes = PVE::Tools::convert_size($vgamem_mb, "mb" => "b");
2186 $memory = ",max_hostmem=$bytes";
2187 } elsif ($qxlnum) {
2188 # from https://www.spice-space.org/multiple-monitors.html
2189 $memory = ",vgamem_mb=$vga->{memory}";
2190 my $ram = $vgamem_mb * 4;
2191 my $vram = $vgamem_mb * 2;
2192 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2193 } else {
2194 $memory = ",vgamem_mb=$vga->{memory}";
2195 }
2196 } elsif ($qxlnum && $id) {
2197 $memory = ",ram_size=67108864,vram_size=33554432";
2198 }
2199
2200 my $q35 = machine_type_is_q35($conf);
2201 my $vgaid = "vga" . ($id // '');
2202 my $pciaddr;
daadd5a4 2203
55655ebc 2204 if ($q35 && $vgaid eq 'vga') {
daadd5a4 2205 # the first display uses pcie.0 bus on q35 machines
d559309f 2206 $pciaddr = print_pcie_addr($vgaid, $bridges, $arch, $machine);
55655ebc 2207 } else {
d559309f 2208 $pciaddr = print_pci_addr($vgaid, $bridges, $arch, $machine);
55655ebc
DC
2209 }
2210
2211 return "$type,id=${vgaid}${memory}${pciaddr}";
2212}
2213
9ed7a77c
WB
2214sub drive_is_cloudinit {
2215 my ($drive) = @_;
2216 return $drive->{file} =~ m@[:/]vm-\d+-cloudinit(?:\.$QEMU_FORMAT_RE)?$@;
2217}
2218
1e3baf05 2219sub drive_is_cdrom {
9c52f5ed
WB
2220 my ($drive, $exclude_cloudinit) = @_;
2221
9ed7a77c 2222 return 0 if $exclude_cloudinit && drive_is_cloudinit($drive);
1e3baf05
DM
2223
2224 return $drive && $drive->{media} && ($drive->{media} eq 'cdrom');
2225
2226}
2227
ffc0d8c7
WB
2228sub parse_number_sets {
2229 my ($set) = @_;
2230 my $res = [];
2231 foreach my $part (split(/;/, $set)) {
2232 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2233 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2234 push @$res, [ $1, $2 ];
2ed5d572 2235 } else {
ffc0d8c7 2236 die "invalid range: $part\n";
2ed5d572
AD
2237 }
2238 }
ffc0d8c7
WB
2239 return $res;
2240}
2ed5d572 2241
ffc0d8c7
WB
2242sub parse_numa {
2243 my ($data) = @_;
2244
2245 my $res = PVE::JSONSchema::parse_property_string($numa_fmt, $data);
2246 $res->{cpus} = parse_number_sets($res->{cpus}) if defined($res->{cpus});
2247 $res->{hostnodes} = parse_number_sets($res->{hostnodes}) if defined($res->{hostnodes});
2ed5d572
AD
2248 return $res;
2249}
2250
040b06b7
DA
2251sub parse_hostpci {
2252 my ($value) = @_;
2253
2254 return undef if !$value;
2255
1f4f447b 2256 my $res = PVE::JSONSchema::parse_property_string($hostpci_fmt, $value);
0cea6a01 2257
1f4f447b
WB
2258 my @idlist = split(/;/, $res->{host});
2259 delete $res->{host};
2260 foreach my $id (@idlist) {
2fd24788
DC
2261 if ($id =~ m/\./) { # full id 00:00.1
2262 push @{$res->{pciid}}, {
2263 id => $id,
2264 };
2265 } else { # partial id 00:00
2266 $res->{pciid} = PVE::SysFSTools::lspci($id);
0cea6a01 2267 }
040b06b7 2268 }
040b06b7
DA
2269 return $res;
2270}
2271
1e3baf05
DM
2272# netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2273sub parse_net {
2274 my ($data) = @_;
2275
cd9c34d1
WB
2276 my $res = eval { PVE::JSONSchema::parse_property_string($net_fmt, $data) };
2277 if ($@) {
2278 warn $@;
2279 return undef;
1e3baf05 2280 }
b5b99790
WB
2281 if (!defined($res->{macaddr})) {
2282 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
2283 $res->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
2284 }
0c9a7596
AD
2285 return $res;
2286}
2287
2288# ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2289sub parse_ipconfig {
2290 my ($data) = @_;
2291
2292 my $res = eval { PVE::JSONSchema::parse_property_string($ipconfig_fmt, $data) };
2293 if ($@) {
2294 warn $@;
2295 return undef;
2296 }
2297
2298 if ($res->{gw} && !$res->{ip}) {
2299 warn 'gateway specified without specifying an IP address';
2300 return undef;
2301 }
2302 if ($res->{gw6} && !$res->{ip6}) {
2303 warn 'IPv6 gateway specified without specifying an IPv6 address';
2304 return undef;
2305 }
2306 if ($res->{gw} && $res->{ip} eq 'dhcp') {
2307 warn 'gateway specified together with DHCP';
2308 return undef;
2309 }
2310 if ($res->{gw6} && $res->{ip6} !~ /^$IPV6RE/) {
2311 # gw6 + auto/dhcp
2312 warn "IPv6 gateway specified together with $res->{ip6} address";
2313 return undef;
2314 }
2315
2316 if (!$res->{ip} && !$res->{ip6}) {
2317 return { ip => 'dhcp', ip6 => 'dhcp' };
2318 }
2319
1e3baf05
DM
2320 return $res;
2321}
2322
2323sub print_net {
2324 my $net = shift;
2325
cd9c34d1 2326 return PVE::JSONSchema::print_property_string($net, $net_fmt);
1e3baf05
DM
2327}
2328
2329sub add_random_macs {
2330 my ($settings) = @_;
2331
2332 foreach my $opt (keys %$settings) {
2333 next if $opt !~ m/^net(\d+)$/;
2334 my $net = parse_net($settings->{$opt});
2335 next if !$net;
2336 $settings->{$opt} = print_net($net);
2337 }
2338}
2339
055d554d
DM
2340sub vm_is_volid_owner {
2341 my ($storecfg, $vmid, $volid) = @_;
2342
2343 if ($volid !~ m|^/|) {
2344 my ($path, $owner);
2345 eval { ($path, $owner) = PVE::Storage::path($storecfg, $volid); };
2346 if ($owner && ($owner == $vmid)) {
2347 return 1;
2348 }
2349 }
2350
2351 return undef;
2352}
2353
055d554d
DM
2354sub vmconfig_register_unused_drive {
2355 my ($storecfg, $vmid, $conf, $drive) = @_;
2356
2d9ddec5
WB
2357 if (drive_is_cloudinit($drive)) {
2358 eval { PVE::Storage::vdisk_free($storecfg, $drive->{file}) };
2359 warn $@ if $@;
2360 } elsif (!drive_is_cdrom($drive)) {
055d554d
DM
2361 my $volid = $drive->{file};
2362 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
8793d495 2363 PVE::QemuConfig->add_unused_volume($conf, $volid, $vmid);
055d554d
DM
2364 }
2365 }
2366}
2367
1f30ac3a 2368# smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str][,base64=bool]
ff6ffe20 2369my $smbios1_fmt = {
bd27e851
WB
2370 uuid => {
2371 type => 'string',
2372 pattern => '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2373 format_description => 'UUID',
52261945 2374 description => "Set SMBIOS1 UUID.",
bd27e851
WB
2375 optional => 1,
2376 },
2377 version => {
2378 type => 'string',
1f30ac3a
CE
2379 pattern => '[A-Za-z0-9+\/]+={0,2}',
2380 format_description => 'Base64 encoded string',
52261945 2381 description => "Set SMBIOS1 version.",
bd27e851
WB
2382 optional => 1,
2383 },
2384 serial => {
2385 type => 'string',
1f30ac3a
CE
2386 pattern => '[A-Za-z0-9+\/]+={0,2}',
2387 format_description => 'Base64 encoded string',
52261945 2388 description => "Set SMBIOS1 serial number.",
bd27e851
WB
2389 optional => 1,
2390 },
2391 manufacturer => {
2392 type => 'string',
1f30ac3a
CE
2393 pattern => '[A-Za-z0-9+\/]+={0,2}',
2394 format_description => 'Base64 encoded string',
52261945 2395 description => "Set SMBIOS1 manufacturer.",
bd27e851
WB
2396 optional => 1,
2397 },
2398 product => {
2399 type => 'string',
1f30ac3a
CE
2400 pattern => '[A-Za-z0-9+\/]+={0,2}',
2401 format_description => 'Base64 encoded string',
52261945 2402 description => "Set SMBIOS1 product ID.",
bd27e851
WB
2403 optional => 1,
2404 },
2405 sku => {
2406 type => 'string',
1f30ac3a
CE
2407 pattern => '[A-Za-z0-9+\/]+={0,2}',
2408 format_description => 'Base64 encoded string',
52261945 2409 description => "Set SMBIOS1 SKU string.",
bd27e851
WB
2410 optional => 1,
2411 },
2412 family => {
2413 type => 'string',
1f30ac3a
CE
2414 pattern => '[A-Za-z0-9+\/]+={0,2}',
2415 format_description => 'Base64 encoded string',
52261945 2416 description => "Set SMBIOS1 family string.",
bd27e851
WB
2417 optional => 1,
2418 },
1f30ac3a
CE
2419 base64 => {
2420 type => 'boolean',
2421 description => 'Flag to indicate that the SMBIOS values are base64 encoded',
2422 optional => 1,
2423 },
2796e7d5
DM
2424};
2425
2796e7d5
DM
2426sub parse_smbios1 {
2427 my ($data) = @_;
2428
ff6ffe20 2429 my $res = eval { PVE::JSONSchema::parse_property_string($smbios1_fmt, $data) };
bd27e851 2430 warn $@ if $@;
2796e7d5
DM
2431 return $res;
2432}
2433
cd11416f
DM
2434sub print_smbios1 {
2435 my ($smbios1) = @_;
ff6ffe20 2436 return PVE::JSONSchema::print_property_string($smbios1, $smbios1_fmt);
cd11416f
DM
2437}
2438
ff6ffe20 2439PVE::JSONSchema::register_format('pve-qm-smbios1', $smbios1_fmt);
2796e7d5 2440
1e3baf05
DM
2441PVE::JSONSchema::register_format('pve-qm-bootdisk', \&verify_bootdisk);
2442sub verify_bootdisk {
2443 my ($value, $noerr) = @_;
2444
74479ee9 2445 return $value if is_valid_drivename($value);
1e3baf05
DM
2446
2447 return undef if $noerr;
2448
2449 die "invalid boot disk '$value'\n";
2450}
2451
0ea9541d
DM
2452sub parse_watchdog {
2453 my ($value) = @_;
2454
2455 return undef if !$value;
2456
ec3582b5
WB
2457 my $res = eval { PVE::JSONSchema::parse_property_string($watchdog_fmt, $value) };
2458 warn $@ if $@;
0ea9541d
DM
2459 return $res;
2460}
2461
9d66b397
SI
2462sub parse_guest_agent {
2463 my ($value) = @_;
2464
2465 return {} if !defined($value->{agent});
2466
2467 my $res = eval { PVE::JSONSchema::parse_property_string($agent_fmt, $value->{agent}) };
2468 warn $@ if $@;
2469
2470 # if the agent is disabled ignore the other potentially set properties
2471 return {} if !$res->{enabled};
2472 return $res;
2473}
2474
55655ebc
DC
2475sub parse_vga {
2476 my ($value) = @_;
2477
2478 return {} if !$value;
2479 my $res = eval { PVE::JSONSchema::parse_property_string($vga_fmt, $value) };
2480 warn $@ if $@;
2481 return $res;
2482}
2483
1e3baf05
DM
2484PVE::JSONSchema::register_format('pve-qm-usb-device', \&verify_usb_device);
2485sub verify_usb_device {
2486 my ($value, $noerr) = @_;
2487
2488 return $value if parse_usb_device($value);
2489
2490 return undef if $noerr;
19672434 2491
1e3baf05
DM
2492 die "unable to parse usb device\n";
2493}
2494
1e3baf05
DM
2495# add JSON properties for create and set function
2496sub json_config_properties {
2497 my $prop = shift;
2498
2499 foreach my $opt (keys %$confdesc) {
c6737ef1 2500 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
1e3baf05
DM
2501 $prop->{$opt} = $confdesc->{$opt};
2502 }
2503
2504 return $prop;
2505}
2506
d41121fd
DM
2507# return copy of $confdesc_cloudinit to generate documentation
2508sub cloudinit_config_properties {
2509
2510 return dclone($confdesc_cloudinit);
2511}
2512
1e3baf05
DM
2513sub check_type {
2514 my ($key, $value) = @_;
2515
2516 die "unknown setting '$key'\n" if !$confdesc->{$key};
2517
2518 my $type = $confdesc->{$key}->{type};
2519
6b64503e 2520 if (!defined($value)) {
1e3baf05
DM
2521 die "got undefined value\n";
2522 }
2523
2524 if ($value =~ m/[\n\r]/) {
2525 die "property contains a line feed\n";
2526 }
2527
2528 if ($type eq 'boolean') {
19672434
DM
2529 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2530 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2531 die "type check ('boolean') failed - got '$value'\n";
1e3baf05
DM
2532 } elsif ($type eq 'integer') {
2533 return int($1) if $value =~ m/^(\d+)$/;
2534 die "type check ('integer') failed - got '$value'\n";
04432191
AD
2535 } elsif ($type eq 'number') {
2536 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2537 die "type check ('number') failed - got '$value'\n";
1e3baf05
DM
2538 } elsif ($type eq 'string') {
2539 if (my $fmt = $confdesc->{$key}->{format}) {
1e3baf05 2540 PVE::JSONSchema::check_format($fmt, $value);
19672434
DM
2541 return $value;
2542 }
1e3baf05 2543 $value =~ s/^\"(.*)\"$/$1/;
19672434 2544 return $value;
1e3baf05
DM
2545 } else {
2546 die "internal error"
2547 }
2548}
2549
1e3baf05
DM
2550sub touch_config {
2551 my ($vmid) = @_;
2552
ffda963f 2553 my $conf = PVE::QemuConfig->config_file($vmid);
1e3baf05
DM
2554 utime undef, undef, $conf;
2555}
2556
1e3baf05 2557sub destroy_vm {
15cc8784 2558 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
1e3baf05 2559
ffda963f 2560 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 2561
ffda963f 2562 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 2563
5e67a2d2
DC
2564 if ($conf->{template}) {
2565 # check if any base image is still used by a linked clone
2566 foreach_drive($conf, sub {
2567 my ($ds, $drive) = @_;
2568
2569 return if drive_is_cdrom($drive);
2570
2571 my $volid = $drive->{file};
2572
2573 return if !$volid || $volid =~ m|^/|;
2574
2575 die "base volume '$volid' is still in use by linked cloned\n"
2576 if PVE::Storage::volume_is_base_and_used($storecfg, $volid);
2577
2578 });
2579 }
2580
19672434 2581 # only remove disks owned by this VM
1e3baf05
DM
2582 foreach_drive($conf, sub {
2583 my ($ds, $drive) = @_;
2584
9c52f5ed 2585 return if drive_is_cdrom($drive, 1);
1e3baf05
DM
2586
2587 my $volid = $drive->{file};
ed221350 2588
ff1a2432 2589 return if !$volid || $volid =~ m|^/|;
1e3baf05 2590
6b64503e 2591 my ($path, $owner) = PVE::Storage::path($storecfg, $volid);
ff1a2432 2592 return if !$path || !$owner || ($owner != $vmid);
1e3baf05 2593
31b52247
FG
2594 eval {
2595 PVE::Storage::vdisk_free($storecfg, $volid);
2596 };
2597 warn "Could not remove disk '$volid', check manually: $@" if $@;
2598
1e3baf05 2599 });
19672434 2600
a6af7b3e 2601 if ($keep_empty_config) {
f73ed6d1 2602 PVE::QemuConfig->write_config($vmid, { memory => 128 });
a6af7b3e 2603 } else {
5172770d 2604 PVE::QemuConfig->destroy_config($vmid);
a6af7b3e 2605 }
1e3baf05
DM
2606
2607 # also remove unused disk
2608 eval {
6b64503e 2609 my $dl = PVE::Storage::vdisk_list($storecfg, undef, $vmid);
1e3baf05
DM
2610
2611 eval {
6b64503e 2612 PVE::Storage::foreach_volid($dl, sub {
1e3baf05 2613 my ($volid, $sid, $volname, $d) = @_;
6b64503e 2614 PVE::Storage::vdisk_free($storecfg, $volid);
1e3baf05
DM
2615 });
2616 };
2617 warn $@ if $@;
2618
2619 };
2620 warn $@ if $@;
2621}
2622
1e3baf05
DM
2623sub parse_vm_config {
2624 my ($filename, $raw) = @_;
2625
2626 return undef if !defined($raw);
2627
554ac7e7 2628 my $res = {
fc1ddcdc 2629 digest => Digest::SHA::sha1_hex($raw),
0d18dcfc 2630 snapshots => {},
0d732d16 2631 pending => {},
554ac7e7 2632 };
1e3baf05 2633
19672434 2634 $filename =~ m|/qemu-server/(\d+)\.conf$|
1e3baf05
DM
2635 || die "got strange filename '$filename'";
2636
2637 my $vmid = $1;
2638
0d18dcfc 2639 my $conf = $res;
b0ec896e 2640 my $descr;
e297c490 2641 my $section = '';
0581fe4f 2642
0d18dcfc
DM
2643 my @lines = split(/\n/, $raw);
2644 foreach my $line (@lines) {
1e3baf05 2645 next if $line =~ m/^\s*$/;
be190583 2646
eab09f4e 2647 if ($line =~ m/^\[PENDING\]\s*$/i) {
e297c490 2648 $section = 'pending';
b0ec896e
DM
2649 if (defined($descr)) {
2650 $descr =~ s/\s+$//;
2651 $conf->{description} = $descr;
2652 }
2653 $descr = undef;
e297c490 2654 $conf = $res->{$section} = {};
eab09f4e
AD
2655 next;
2656
0d732d16 2657 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
e297c490 2658 $section = $1;
b0ec896e
DM
2659 if (defined($descr)) {
2660 $descr =~ s/\s+$//;
2661 $conf->{description} = $descr;
2662 }
2663 $descr = undef;
e297c490 2664 $conf = $res->{snapshots}->{$section} = {};
0d18dcfc
DM
2665 next;
2666 }
1e3baf05 2667
0581fe4f 2668 if ($line =~ m/^\#(.*)\s*$/) {
b0ec896e 2669 $descr = '' if !defined($descr);
0581fe4f
DM
2670 $descr .= PVE::Tools::decode_text($1) . "\n";
2671 next;
2672 }
2673
1e3baf05 2674 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
b0ec896e 2675 $descr = '' if !defined($descr);
0581fe4f 2676 $descr .= PVE::Tools::decode_text($2);
0d18dcfc
DM
2677 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2678 $conf->{snapstate} = $1;
1e3baf05
DM
2679 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2680 my $key = $1;
2681 my $value = $2;
0d18dcfc 2682 $conf->{$key} = $value;
ef824322 2683 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
e297c490 2684 my $value = $1;
ef824322
DM
2685 if ($section eq 'pending') {
2686 $conf->{delete} = $value; # we parse this later
2687 } else {
2688 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
eab09f4e 2689 }
15cf7698 2690 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
1e3baf05
DM
2691 my $key = $1;
2692 my $value = $2;
2693 eval { $value = check_type($key, $value); };
2694 if ($@) {
2695 warn "vm $vmid - unable to parse value of '$key' - $@";
2696 } else {
b799312f 2697 $key = 'ide2' if $key eq 'cdrom';
1e3baf05 2698 my $fmt = $confdesc->{$key}->{format};
b799312f 2699 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
1e3baf05
DM
2700 my $v = parse_drive($key, $value);
2701 if (my $volid = filename_to_volume_id($vmid, $v->{file}, $v->{media})) {
2702 $v->{file} = $volid;
6b64503e 2703 $value = print_drive($vmid, $v);
1e3baf05
DM
2704 } else {
2705 warn "vm $vmid - unable to parse value of '$key'\n";
2706 next;
2707 }
2708 }
2709
b799312f 2710 $conf->{$key} = $value;
1e3baf05
DM
2711 }
2712 }
2713 }
2714
b0ec896e
DM
2715 if (defined($descr)) {
2716 $descr =~ s/\s+$//;
2717 $conf->{description} = $descr;
2718 }
0d18dcfc 2719 delete $res->{snapstate}; # just to be sure
1e3baf05
DM
2720
2721 return $res;
2722}
2723
1858638f
DM
2724sub write_vm_config {
2725 my ($filename, $conf) = @_;
1e3baf05 2726
0d18dcfc
DM
2727 delete $conf->{snapstate}; # just to be sure
2728
1858638f
DM
2729 if ($conf->{cdrom}) {
2730 die "option ide2 conflicts with cdrom\n" if $conf->{ide2};
2731 $conf->{ide2} = $conf->{cdrom};
2732 delete $conf->{cdrom};
2733 }
1e3baf05
DM
2734
2735 # we do not use 'smp' any longer
1858638f
DM
2736 if ($conf->{sockets}) {
2737 delete $conf->{smp};
2738 } elsif ($conf->{smp}) {
2739 $conf->{sockets} = $conf->{smp};
2740 delete $conf->{cores};
2741 delete $conf->{smp};
1e3baf05
DM
2742 }
2743
ee2f90b1 2744 my $used_volids = {};
0d18dcfc 2745
ee2f90b1 2746 my $cleanup_config = sub {
ef824322 2747 my ($cref, $pending, $snapname) = @_;
1858638f 2748
ee2f90b1
DM
2749 foreach my $key (keys %$cref) {
2750 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
ef824322 2751 $key eq 'snapstate' || $key eq 'pending';
ee2f90b1 2752 my $value = $cref->{$key};
ef824322
DM
2753 if ($key eq 'delete') {
2754 die "propertry 'delete' is only allowed in [PENDING]\n"
2755 if !$pending;
2756 # fixme: check syntax?
2757 next;
2758 }
ee2f90b1
DM
2759 eval { $value = check_type($key, $value); };
2760 die "unable to parse value of '$key' - $@" if $@;
1858638f 2761
ee2f90b1
DM
2762 $cref->{$key} = $value;
2763
74479ee9 2764 if (!$snapname && is_valid_drivename($key)) {
ed221350 2765 my $drive = parse_drive($key, $value);
ee2f90b1
DM
2766 $used_volids->{$drive->{file}} = 1 if $drive && $drive->{file};
2767 }
1e3baf05 2768 }
ee2f90b1
DM
2769 };
2770
2771 &$cleanup_config($conf);
ef824322
DM
2772
2773 &$cleanup_config($conf->{pending}, 1);
2774
ee2f90b1 2775 foreach my $snapname (keys %{$conf->{snapshots}}) {
ef824322
DM
2776 die "internal error" if $snapname eq 'pending';
2777 &$cleanup_config($conf->{snapshots}->{$snapname}, undef, $snapname);
1e3baf05
DM
2778 }
2779
1858638f
DM
2780 # remove 'unusedX' settings if we re-add a volume
2781 foreach my $key (keys %$conf) {
2782 my $value = $conf->{$key};
ee2f90b1 2783 if ($key =~ m/^unused/ && $used_volids->{$value}) {
1858638f 2784 delete $conf->{$key};
1e3baf05 2785 }
1858638f 2786 }
be190583 2787
0d18dcfc 2788 my $generate_raw_config = sub {
b0ec896e 2789 my ($conf, $pending) = @_;
0581fe4f 2790
0d18dcfc
DM
2791 my $raw = '';
2792
2793 # add description as comment to top of file
b0ec896e
DM
2794 if (defined(my $descr = $conf->{description})) {
2795 if ($descr) {
2796 foreach my $cl (split(/\n/, $descr)) {
2797 $raw .= '#' . PVE::Tools::encode_text($cl) . "\n";
2798 }
2799 } else {
2800 $raw .= "#\n" if $pending;
2801 }
0d18dcfc
DM
2802 }
2803
2804 foreach my $key (sort keys %$conf) {
ef824322 2805 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
0d18dcfc
DM
2806 $raw .= "$key: $conf->{$key}\n";
2807 }
2808 return $raw;
2809 };
0581fe4f 2810
0d18dcfc 2811 my $raw = &$generate_raw_config($conf);
ef824322
DM
2812
2813 if (scalar(keys %{$conf->{pending}})){
2814 $raw .= "\n[PENDING]\n";
b0ec896e 2815 $raw .= &$generate_raw_config($conf->{pending}, 1);
ef824322
DM
2816 }
2817
0d18dcfc
DM
2818 foreach my $snapname (sort keys %{$conf->{snapshots}}) {
2819 $raw .= "\n[$snapname]\n";
2820 $raw .= &$generate_raw_config($conf->{snapshots}->{$snapname});
1858638f 2821 }
1e3baf05 2822
1858638f
DM
2823 return $raw;
2824}
1e3baf05 2825
19672434 2826sub load_defaults {
1e3baf05
DM
2827
2828 my $res = {};
2829
2830 # we use static defaults from our JSON schema configuration
2831 foreach my $key (keys %$confdesc) {
2832 if (defined(my $default = $confdesc->{$key}->{default})) {
2833 $res->{$key} = $default;
2834 }
2835 }
19672434 2836
1e3baf05
DM
2837 return $res;
2838}
2839
2840sub config_list {
2841 my $vmlist = PVE::Cluster::get_vmlist();
2842 my $res = {};
2843 return $res if !$vmlist || !$vmlist->{ids};
2844 my $ids = $vmlist->{ids};
2845
1e3baf05
DM
2846 foreach my $vmid (keys %$ids) {
2847 my $d = $ids->{$vmid};
2848 next if !$d->{node} || $d->{node} ne $nodename;
5ee957cc 2849 next if !$d->{type} || $d->{type} ne 'qemu';
1e3baf05
DM
2850 $res->{$vmid}->{exists} = 1;
2851 }
2852 return $res;
2853}
2854
64e13401
DM
2855# test if VM uses local resources (to prevent migration)
2856sub check_local_resources {
2857 my ($conf, $noerr) = @_;
2858
ca6abacf 2859 my @loc_res = ();
19672434 2860
ca6abacf
TM
2861 push @loc_res, "hostusb" if $conf->{hostusb}; # old syntax
2862 push @loc_res, "hostpci" if $conf->{hostpci}; # old syntax
64e13401 2863
ca6abacf 2864 push @loc_res, "ivshmem" if $conf->{ivshmem};
6dbcb073 2865
0d29ab3b 2866 foreach my $k (keys %$conf) {
a9ce7583 2867 next if $k =~ m/^usb/ && ($conf->{$k} =~ m/^spice(?![^,])/);
d44712fc
EK
2868 # sockets are safe: they will recreated be on the target side post-migrate
2869 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
ca6abacf 2870 push @loc_res, $k if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
64e13401
DM
2871 }
2872
ca6abacf 2873 die "VM uses local resources\n" if scalar @loc_res && !$noerr;
64e13401 2874
ca6abacf 2875 return \@loc_res;
64e13401
DM
2876}
2877
719893a9 2878# check if used storages are available on all nodes (use by migrate)
47152e2e
DM
2879sub check_storage_availability {
2880 my ($storecfg, $conf, $node) = @_;
2881
2882 foreach_drive($conf, sub {
2883 my ($ds, $drive) = @_;
2884
2885 my $volid = $drive->{file};
2886 return if !$volid;
2887
2888 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2889 return if !$sid;
2890
2891 # check if storage is available on both nodes
2892 my $scfg = PVE::Storage::storage_check_node($storecfg, $sid);
2893 PVE::Storage::storage_check_node($storecfg, $sid, $node);
2894 });
2895}
2896
719893a9
DM
2897# list nodes where all VM images are available (used by has_feature API)
2898sub shared_nodes {
2899 my ($conf, $storecfg) = @_;
2900
2901 my $nodelist = PVE::Cluster::get_nodelist();
2902 my $nodehash = { map { $_ => 1 } @$nodelist };
2903 my $nodename = PVE::INotify::nodename();
be190583 2904
719893a9
DM
2905 foreach_drive($conf, sub {
2906 my ($ds, $drive) = @_;
2907
2908 my $volid = $drive->{file};
2909 return if !$volid;
2910
2911 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2912 if ($storeid) {
2913 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2914 if ($scfg->{disable}) {
2915 $nodehash = {};
2916 } elsif (my $avail = $scfg->{nodes}) {
2917 foreach my $node (keys %$nodehash) {
2918 delete $nodehash->{$node} if !$avail->{$node};
2919 }
2920 } elsif (!$scfg->{shared}) {
2921 foreach my $node (keys %$nodehash) {
2922 delete $nodehash->{$node} if $node ne $nodename
2923 }
2924 }
2925 }
2926 });
2927
2928 return $nodehash
2929}
2930
f25852c2
TM
2931sub check_local_storage_availability {
2932 my ($conf, $storecfg) = @_;
2933
2934 my $nodelist = PVE::Cluster::get_nodelist();
2935 my $nodehash = { map { $_ => {} } @$nodelist };
2936
2937 foreach_drive($conf, sub {
2938 my ($ds, $drive) = @_;
2939
2940 my $volid = $drive->{file};
2941 return if !$volid;
2942
2943 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
2944 if ($storeid) {
2945 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
2946
2947 if ($scfg->{disable}) {
2948 foreach my $node (keys %$nodehash) {
32075a2c 2949 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2950 }
2951 } elsif (my $avail = $scfg->{nodes}) {
2952 foreach my $node (keys %$nodehash) {
2953 if (!$avail->{$node}) {
32075a2c 2954 $nodehash->{$node}->{unavailable_storages}->{$storeid} = 1;
f25852c2
TM
2955 }
2956 }
2957 }
2958 }
2959 });
2960
32075a2c
TL
2961 foreach my $node (values %$nodehash) {
2962 if (my $unavail = $node->{unavailable_storages}) {
2963 $node->{unavailable_storages} = [ sort keys %$unavail ];
2964 }
2965 }
2966
f25852c2
TM
2967 return $nodehash
2968}
2969
1e3baf05
DM
2970sub check_cmdline {
2971 my ($pidfile, $pid) = @_;
2972
6b64503e
DM
2973 my $fh = IO::File->new("/proc/$pid/cmdline", "r");
2974 if (defined($fh)) {
1e3baf05
DM
2975 my $line = <$fh>;
2976 $fh->close;
2977 return undef if !$line;
6b64503e 2978 my @param = split(/\0/, $line);
1e3baf05
DM
2979
2980 my $cmd = $param[0];
6908fd9b 2981 return if !$cmd || ($cmd !~ m|kvm$| && $cmd !~ m@(?:^|/)qemu-system-[^/]+$@);
1e3baf05
DM
2982
2983 for (my $i = 0; $i < scalar (@param); $i++) {
2984 my $p = $param[$i];
2985 next if !$p;
2986 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2987 my $p = $param[$i+1];
2988 return 1 if $p && ($p eq $pidfile);
2989 return undef;
2990 }
2991 }
2992 }
2993 return undef;
2994}
2995
2996sub check_running {
7e8dcf2c 2997 my ($vmid, $nocheck, $node) = @_;
1e3baf05 2998
ffda963f 2999 my $filename = PVE::QemuConfig->config_file($vmid, $node);
1e3baf05
DM
3000
3001 die "unable to find configuration file for VM $vmid - no such machine\n"
e6c3b671 3002 if !$nocheck && ! -f $filename;
1e3baf05 3003
e6c3b671 3004 my $pidfile = pidfile_name($vmid);
1e3baf05 3005
e6c3b671
DM
3006 if (my $fd = IO::File->new("<$pidfile")) {
3007 my $st = stat($fd);
1e3baf05 3008 my $line = <$fd>;
6b64503e 3009 close($fd);
1e3baf05
DM
3010
3011 my $mtime = $st->mtime;
3012 if ($mtime > time()) {
3013 warn "file '$filename' modified in future\n";
3014 }
3015
3016 if ($line =~ m/^(\d+)$/) {
3017 my $pid = $1;
e6c3b671
DM
3018 if (check_cmdline($pidfile, $pid)) {
3019 if (my $pinfo = PVE::ProcFSTools::check_process_running($pid)) {
3020 return $pid;
3021 }
3022 }
1e3baf05
DM
3023 }
3024 }
3025
3026 return undef;
3027}
3028
3029sub vzlist {
19672434 3030
1e3baf05
DM
3031 my $vzlist = config_list();
3032
6b64503e 3033 my $fd = IO::Dir->new($var_run_tmpdir) || return $vzlist;
1e3baf05 3034
19672434 3035 while (defined(my $de = $fd->read)) {
1e3baf05
DM
3036 next if $de !~ m/^(\d+)\.pid$/;
3037 my $vmid = $1;
6b64503e
DM
3038 next if !defined($vzlist->{$vmid});
3039 if (my $pid = check_running($vmid)) {
1e3baf05
DM
3040 $vzlist->{$vmid}->{pid} = $pid;
3041 }
3042 }
3043
3044 return $vzlist;
3045}
3046
1e3baf05
DM
3047sub disksize {
3048 my ($storecfg, $conf) = @_;
3049
3050 my $bootdisk = $conf->{bootdisk};
3051 return undef if !$bootdisk;
74479ee9 3052 return undef if !is_valid_drivename($bootdisk);
1e3baf05
DM
3053
3054 return undef if !$conf->{$bootdisk};
3055
3056 my $drive = parse_drive($bootdisk, $conf->{$bootdisk});
3057 return undef if !defined($drive);
3058
3059 return undef if drive_is_cdrom($drive);
3060
3061 my $volid = $drive->{file};
3062 return undef if !$volid;
3063
24afaca0 3064 return $drive->{size};
1e3baf05
DM
3065}
3066
b1a70cab
DM
3067our $vmstatus_return_properties = {
3068 vmid => get_standard_option('pve-vmid'),
3069 status => {
3070 description => "Qemu process status.",
3071 type => 'string',
3072 enum => ['stopped', 'running'],
3073 },
3074 maxmem => {
3075 description => "Maximum memory in bytes.",
3076 type => 'integer',
3077 optional => 1,
3078 renderer => 'bytes',
3079 },
3080 maxdisk => {
3081 description => "Root disk size in bytes.",
3082 type => 'integer',
3083 optional => 1,
3084 renderer => 'bytes',
3085 },
3086 name => {
3087 description => "VM name.",
3088 type => 'string',
3089 optional => 1,
3090 },
3091 qmpstatus => {
3092 description => "Qemu QMP agent status.",
3093 type => 'string',
3094 optional => 1,
3095 },
3096 pid => {
3097 description => "PID of running qemu process.",
3098 type => 'integer',
3099 optional => 1,
3100 },
3101 uptime => {
3102 description => "Uptime.",
3103 type => 'integer',
3104 optional => 1,
3105 renderer => 'duration',
3106 },
3107 cpus => {
3108 description => "Maximum usable CPUs.",
3109 type => 'number',
3110 optional => 1,
3111 },
e6ed61b4 3112 lock => {
11efdfa5 3113 description => "The current config lock, if any.",
e6ed61b4
DC
3114 type => 'string',
3115 optional => 1,
3116 }
b1a70cab
DM
3117};
3118
1e3baf05
DM
3119my $last_proc_pid_stat;
3120
03a33f30
DM
3121# get VM status information
3122# This must be fast and should not block ($full == false)
3123# We only query KVM using QMP if $full == true (this can be slow)
1e3baf05 3124sub vmstatus {
03a33f30 3125 my ($opt_vmid, $full) = @_;
1e3baf05
DM
3126
3127 my $res = {};
3128
19672434 3129 my $storecfg = PVE::Storage::config();
1e3baf05
DM
3130
3131 my $list = vzlist();
3618ee99
EK
3132 my $defaults = load_defaults();
3133
694fcad4 3134 my ($uptime) = PVE::ProcFSTools::read_proc_uptime(1);
1e3baf05 3135
ae4915a2
DM
3136 my $cpucount = $cpuinfo->{cpus} || 1;
3137
1e3baf05
DM
3138 foreach my $vmid (keys %$list) {
3139 next if $opt_vmid && ($vmid ne $opt_vmid);
3140
ffda963f 3141 my $cfspath = PVE::QemuConfig->cfs_config_path($vmid);
1e3baf05
DM
3142 my $conf = PVE::Cluster::cfs_read_file($cfspath) || {};
3143
b1a70cab 3144 my $d = { vmid => $vmid };
1e3baf05
DM
3145 $d->{pid} = $list->{$vmid}->{pid};
3146
3147 # fixme: better status?
3148 $d->{status} = $list->{$vmid}->{pid} ? 'running' : 'stopped';
3149
af990afe
DM
3150 my $size = disksize($storecfg, $conf);
3151 if (defined($size)) {
3152 $d->{disk} = 0; # no info available
1e3baf05
DM
3153 $d->{maxdisk} = $size;
3154 } else {
3155 $d->{disk} = 0;
3156 $d->{maxdisk} = 0;
3157 }
3158
3618ee99
EK
3159 $d->{cpus} = ($conf->{sockets} || $defaults->{sockets})
3160 * ($conf->{cores} || $defaults->{cores});
ae4915a2 3161 $d->{cpus} = $cpucount if $d->{cpus} > $cpucount;
d7c8364b 3162 $d->{cpus} = $conf->{vcpus} if $conf->{vcpus};
ae4915a2 3163
1e3baf05 3164 $d->{name} = $conf->{name} || "VM $vmid";
3618ee99
EK
3165 $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024)
3166 : $defaults->{memory}*(1024*1024);
1e3baf05 3167
8b1accf7 3168 if ($conf->{balloon}) {
4bdb0514 3169 $d->{balloon_min} = $conf->{balloon}*(1024*1024);
3618ee99
EK
3170 $d->{shares} = defined($conf->{shares}) ? $conf->{shares}
3171 : $defaults->{shares};
8b1accf7
DM
3172 }
3173
1e3baf05
DM
3174 $d->{uptime} = 0;
3175 $d->{cpu} = 0;
1e3baf05
DM
3176 $d->{mem} = 0;
3177
3178 $d->{netout} = 0;
3179 $d->{netin} = 0;
3180
3181 $d->{diskread} = 0;
3182 $d->{diskwrite} = 0;
3183
ffda963f 3184 $d->{template} = PVE::QemuConfig->is_template($conf);
4d8c851b 3185
8107b378 3186 $d->{serial} = 1 if conf_has_serial($conf);
e6ed61b4 3187 $d->{lock} = $conf->{lock} if $conf->{lock};
8107b378 3188
1e3baf05
DM
3189 $res->{$vmid} = $d;
3190 }
3191
3192 my $netdev = PVE::ProcFSTools::read_proc_net_dev();
3193 foreach my $dev (keys %$netdev) {
3194 next if $dev !~ m/^tap([1-9]\d*)i/;
3195 my $vmid = $1;
3196 my $d = $res->{$vmid};
3197 next if !$d;
19672434 3198
1e3baf05
DM
3199 $d->{netout} += $netdev->{$dev}->{receive};
3200 $d->{netin} += $netdev->{$dev}->{transmit};
604ea644
AD
3201
3202 if ($full) {
3203 $d->{nics}->{$dev}->{netout} = $netdev->{$dev}->{receive};
3204 $d->{nics}->{$dev}->{netin} = $netdev->{$dev}->{transmit};
3205 }
3206
1e3baf05
DM
3207 }
3208
1e3baf05
DM
3209 my $ctime = gettimeofday;
3210
3211 foreach my $vmid (keys %$list) {
3212
3213 my $d = $res->{$vmid};
3214 my $pid = $d->{pid};
3215 next if !$pid;
3216
694fcad4
DM
3217 my $pstat = PVE::ProcFSTools::read_proc_pid_stat($pid);
3218 next if !$pstat; # not running
19672434 3219
694fcad4 3220 my $used = $pstat->{utime} + $pstat->{stime};
1e3baf05 3221
694fcad4 3222 $d->{uptime} = int(($uptime - $pstat->{starttime})/$cpuinfo->{user_hz});
1e3baf05 3223
694fcad4 3224 if ($pstat->{vsize}) {
6b64503e 3225 $d->{mem} = int(($pstat->{rss}/$pstat->{vsize})*$d->{maxmem});
1e3baf05
DM
3226 }
3227
3228 my $old = $last_proc_pid_stat->{$pid};
3229 if (!$old) {
19672434
DM
3230 $last_proc_pid_stat->{$pid} = {
3231 time => $ctime,
1e3baf05
DM
3232 used => $used,
3233 cpu => 0,
1e3baf05
DM
3234 };
3235 next;
3236 }
3237
7f0b5beb 3238 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz};
1e3baf05
DM
3239
3240 if ($dtime > 1000) {
3241 my $dutime = $used - $old->{used};
3242
ae4915a2 3243 $d->{cpu} = (($dutime/$dtime)* $cpucount) / $d->{cpus};
1e3baf05 3244 $last_proc_pid_stat->{$pid} = {
19672434 3245 time => $ctime,
1e3baf05
DM
3246 used => $used,
3247 cpu => $d->{cpu},
1e3baf05
DM
3248 };
3249 } else {
3250 $d->{cpu} = $old->{cpu};
1e3baf05
DM
3251 }
3252 }
3253
f5eb281a 3254 return $res if !$full;
03a33f30
DM
3255
3256 my $qmpclient = PVE::QMPClient->new();
3257
64e7fcf2
DM
3258 my $ballooncb = sub {
3259 my ($vmid, $resp) = @_;
3260
3261 my $info = $resp->{'return'};
38babf81
DM
3262 return if !$info->{max_mem};
3263
64e7fcf2
DM
3264 my $d = $res->{$vmid};
3265
38babf81
DM
3266 # use memory assigned to VM
3267 $d->{maxmem} = $info->{max_mem};
3268 $d->{balloon} = $info->{actual};
3269
3270 if (defined($info->{total_mem}) && defined($info->{free_mem})) {
3271 $d->{mem} = $info->{total_mem} - $info->{free_mem};
3272 $d->{freemem} = $info->{free_mem};
64e7fcf2
DM
3273 }
3274
604ea644 3275 $d->{ballooninfo} = $info;
64e7fcf2
DM
3276 };
3277
03a33f30
DM
3278 my $blockstatscb = sub {
3279 my ($vmid, $resp) = @_;
3280 my $data = $resp->{'return'} || [];
3281 my $totalrdbytes = 0;
3282 my $totalwrbytes = 0;
604ea644 3283
03a33f30
DM
3284 for my $blockstat (@$data) {
3285 $totalrdbytes = $totalrdbytes + $blockstat->{stats}->{rd_bytes};
3286 $totalwrbytes = $totalwrbytes + $blockstat->{stats}->{wr_bytes};
604ea644
AD
3287
3288 $blockstat->{device} =~ s/drive-//;
3289 $res->{$vmid}->{blockstat}->{$blockstat->{device}} = $blockstat->{stats};
03a33f30
DM
3290 }
3291 $res->{$vmid}->{diskread} = $totalrdbytes;
3292 $res->{$vmid}->{diskwrite} = $totalwrbytes;
3293 };
3294
3295 my $statuscb = sub {
3296 my ($vmid, $resp) = @_;
64e7fcf2 3297
03a33f30 3298 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
64e7fcf2
DM
3299 # this fails if ballon driver is not loaded, so this must be
3300 # the last commnand (following command are aborted if this fails).
38babf81 3301 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
03a33f30
DM
3302
3303 my $status = 'unknown';
3304 if (!defined($status = $resp->{'return'}->{status})) {
3305 warn "unable to get VM status\n";
3306 return;
3307 }
3308
3309 $res->{$vmid}->{qmpstatus} = $resp->{'return'}->{status};
3310 };
3311
3312 foreach my $vmid (keys %$list) {
3313 next if $opt_vmid && ($vmid ne $opt_vmid);
3314 next if !$res->{$vmid}->{pid}; # not running
3315 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3316 }
3317
b017fbda 3318 $qmpclient->queue_execute(undef, 2);
03a33f30
DM
3319
3320 foreach my $vmid (keys %$list) {
3321 next if $opt_vmid && ($vmid ne $opt_vmid);
3322 $res->{$vmid}->{qmpstatus} = $res->{$vmid}->{status} if !$res->{$vmid}->{qmpstatus};
3323 }
3324
1e3baf05
DM
3325 return $res;
3326}
3327
3328sub foreach_drive {
b74ff047 3329 my ($conf, $func, @param) = @_;
1e3baf05 3330
74479ee9
FG
3331 foreach my $ds (valid_drive_names()) {
3332 next if !defined($conf->{$ds});
1e3baf05 3333
6b64503e 3334 my $drive = parse_drive($ds, $conf->{$ds});
1e3baf05
DM
3335 next if !$drive;
3336
b74ff047 3337 &$func($ds, $drive, @param);
1e3baf05
DM
3338 }
3339}
3340
d5769dc2 3341sub foreach_volid {
b6adff33 3342 my ($conf, $func, @param) = @_;
be190583 3343
d5769dc2
DM
3344 my $volhash = {};
3345
3346 my $test_volid = sub {
c272ba8d 3347 my ($volid, $is_cdrom, $replicate, $shared, $snapname, $size) = @_;
d5769dc2
DM
3348
3349 return if !$volid;
be190583 3350
392f8b5d
DM
3351 $volhash->{$volid}->{cdrom} //= 1;
3352 $volhash->{$volid}->{cdrom} = 0 if !$is_cdrom;
3353
3354 $volhash->{$volid}->{replicate} //= 0;
3355 $volhash->{$volid}->{replicate} = 1 if $replicate;
39019f75 3356
ec82e3ee
CH
3357 $volhash->{$volid}->{shared} //= 0;
3358 $volhash->{$volid}->{shared} = 1 if $shared;
3359
39019f75
DM
3360 $volhash->{$volid}->{referenced_in_config} //= 0;
3361 $volhash->{$volid}->{referenced_in_config} = 1 if !defined($snapname);
3362
3363 $volhash->{$volid}->{referenced_in_snapshot}->{$snapname} = 1
3364 if defined($snapname);
c272ba8d 3365 $volhash->{$volid}->{size} = $size if $size;
d5769dc2
DM
3366 };
3367
ed221350 3368 foreach_drive($conf, sub {
d5769dc2 3369 my ($ds, $drive) = @_;
c272ba8d 3370 $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, undef, $drive->{size});
d5769dc2
DM
3371 });
3372
3373 foreach my $snapname (keys %{$conf->{snapshots}}) {
3374 my $snap = $conf->{snapshots}->{$snapname};
39019f75 3375 $test_volid->($snap->{vmstate}, 0, 1, $snapname);
ed221350 3376 foreach_drive($snap, sub {
d5769dc2 3377 my ($ds, $drive) = @_;
ec82e3ee 3378 $test_volid->($drive->{file}, drive_is_cdrom($drive), $drive->{replicate} // 1, $drive->{shared}, $snapname);
d5769dc2
DM
3379 });
3380 }
3381
3382 foreach my $volid (keys %$volhash) {
b6adff33 3383 &$func($volid, $volhash->{$volid}, @param);
d5769dc2
DM
3384 }
3385}
3386
8107b378
DC
3387sub conf_has_serial {
3388 my ($conf) = @_;
3389
3390 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3391 if ($conf->{"serial$i"}) {
3392 return 1;
3393 }
3394 }
3395
3396 return 0;
3397}
3398
d5535a00
TL
3399sub conf_has_audio {
3400 my ($conf, $id) = @_;
3401
3402 $id //= 0;
3403 my $audio = $conf->{"audio$id"};
3404 return undef if !defined($audio);
3405
3406 my $audioproperties = PVE::JSONSchema::parse_property_string($audio_fmt, $audio);
3407 my $audiodriver = $audioproperties->{driver} // 'spice';
3408
3409 return {
3410 dev => $audioproperties->{device},
b0f96836 3411 dev_id => "audiodev$id",
d5535a00
TL
3412 backend => $audiodriver,
3413 backend_id => "$audiodriver-backend${id}",
3414 };
3415}
3416
86b8228b
DM
3417sub vga_conf_has_spice {
3418 my ($vga) = @_;
3419
55655ebc
DC
3420 my $vgaconf = parse_vga($vga);
3421 my $vgatype = $vgaconf->{type};
3422 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
590e698c
DM
3423
3424 return $1 || 1;
86b8228b
DM
3425}
3426
d731ecbe
WB
3427my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3428sub get_host_arch() {
3429 $host_arch = (POSIX::uname())[4] if !$host_arch;
3430 return $host_arch;
3431}
3432
3433sub is_native($) {
3434 my ($arch) = @_;
3435 return get_host_arch() eq $arch;
3436}
3437
3438my $default_machines = {
3439 x86_64 => 'pc',
3440 aarch64 => 'virt',
3441};
3442
3443sub get_basic_machine_info {
3444 my ($conf, $forcemachine) = @_;
3445
3446 my $arch = $conf->{arch} // get_host_arch();
3447 my $machine = $forcemachine || $conf->{machine} || $default_machines->{$arch};
3448 return ($arch, $machine);
3449}
3450
96ed3574
WB
3451sub get_ovmf_files($) {
3452 my ($arch) = @_;
3453
3454 my $ovmf = $OVMF->{$arch}
3455 or die "no OVMF images known for architecture '$arch'\n";
3456
3457 return @$ovmf;
3458}
3459
6908fd9b
WB
3460my $Arch2Qemu = {
3461 aarch64 => '/usr/bin/qemu-system-aarch64',
3462 x86_64 => '/usr/bin/qemu-system-x86_64',
3463};
3464sub get_command_for_arch($) {
3465 my ($arch) = @_;
3466 return '/usr/bin/kvm' if is_native($arch);
3467
3468 my $cmd = $Arch2Qemu->{$arch}
3469 or die "don't know how to emulate architecture '$arch'\n";
3470 return $cmd;
3471}
3472
4fc262bd
WB
3473sub get_cpu_options {
3474 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3475
3476 my $cpuFlags = [];
3477 my $ostype = $conf->{ostype};
3478
3479 my $cpu = $kvm ? "kvm64" : "qemu64";
0f27a91d
WB
3480 if ($arch eq 'aarch64') {
3481 $cpu = 'cortex-a57';
3482 }
2894c247 3483 my $hv_vendor_id;
4fc262bd
WB
3484 if (my $cputype = $conf->{cpu}) {
3485 my $cpuconf = PVE::JSONSchema::parse_property_string($cpu_fmt, $cputype)
3486 or die "Cannot parse cpu description: $cputype\n";
3487 $cpu = $cpuconf->{cputype};
3488 $kvm_off = 1 if $cpuconf->{hidden};
2894c247 3489 $hv_vendor_id = $cpuconf->{'hv-vendor-id'};
4fc262bd
WB
3490
3491 if (defined(my $flags = $cpuconf->{flags})) {
3492 push @$cpuFlags, split(";", $flags);
3493 }
3494 }
3495
1ea63c15 3496 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
4fc262bd
WB
3497
3498 push @$cpuFlags , '-x2apic'
3499 if $conf->{ostype} && $conf->{ostype} eq 'solaris';
3500
3501 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3502
3503 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3504
1ea63c15 3505 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
4fc262bd
WB
3506
3507 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3508 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3509 }
3510
2894c247 3511 add_hyperv_enlightenments($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios}, $gpu_passthrough, $hv_vendor_id) if $kvm;
4fc262bd 3512
1ea63c15 3513 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
4fc262bd
WB
3514
3515 push @$cpuFlags, 'kvm=off' if $kvm_off;
3516
3517 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3518 push @$cpuFlags, "vendor=${cpu_vendor}"
3519 if $cpu_vendor ne 'default';
3520 } elsif ($arch ne 'aarch64') {
3521 die "internal error"; # should not happen
3522 }
3523
3524 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3525
3526 return ('-cpu', $cpu);
3527}
3528
1e3baf05 3529sub config_to_command {
67812f9c 3530 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
1e3baf05
DM
3531
3532 my $cmd = [];
8c559505
DM
3533 my $globalFlags = [];
3534 my $machineFlags = [];
3535 my $rtcFlags = [];
5bdcf937 3536 my $devices = [];
b78ebef7 3537 my $pciaddr = '';
5bdcf937 3538 my $bridges = {};
1e3baf05 3539 my $vernum = 0; # unknown
b42d3cf9 3540 my $ostype = $conf->{ostype};
4317f69f 3541 my $winversion = windows_version($ostype);
d731ecbe
WB
3542 my $kvm = $conf->{kvm};
3543
3544 my ($arch, $machine_type) = get_basic_machine_info($conf, $forcemachine);
1476b99f
DC
3545 my $kvm_binary = get_command_for_arch($arch);
3546 my $kvmver = kvm_user_version($kvm_binary);
d731ecbe 3547 $kvm //= 1 if is_native($arch);
4317f69f 3548
d731ecbe
WB
3549 if ($kvm) {
3550 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3551 if !defined kvm_version();
3552 }
bfcd9b7e 3553
a3c52213
DM
3554 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3555 $vernum = $1*1000000+$2*1000;
3556 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
1e3baf05
DM
3557 $vernum = $1*1000000+$2*1000+$3;
3558 }
3559
a3c52213 3560 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
1e3baf05 3561
db656e5f 3562 my $q35 = machine_type_is_q35($conf);
4d3f29ed 3563 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
249c4a6c
AD
3564 my $use_old_bios_files = undef;
3565 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
db656e5f 3566
f08e17c7
AD
3567 my $cpuunits = defined($conf->{cpuunits}) ?
3568 $conf->{cpuunits} : $defaults->{cpuunits};
3569
1476b99f 3570 push @$cmd, $kvm_binary;
1e3baf05
DM
3571
3572 push @$cmd, '-id', $vmid;
3573
e4d4cda1
HR
3574 my $vmname = $conf->{name} || "vm$vmid";
3575
3576 push @$cmd, '-name', $vmname;
3577
1e3baf05
DM
3578 my $use_virtio = 0;
3579
c971c4f2
AD
3580 my $qmpsocket = qmp_socket($vmid);
3581 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3582 push @$cmd, '-mon', "chardev=qmp,mode=control";
3583
71bd73b5 3584 if (qemu_machine_feature_enabled($machine_type, $kvmver, 2, 12)) {
b4496b9e 3585 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
71bd73b5
DC
3586 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3587 }
1e3baf05 3588
6b64503e 3589 push @$cmd, '-pidfile' , pidfile_name($vmid);
19672434 3590
1e3baf05
DM
3591 push @$cmd, '-daemonize';
3592
2796e7d5 3593 if ($conf->{smbios1}) {
1f30ac3a
CE
3594 my $smbios_conf = parse_smbios1($conf->{smbios1});
3595 if ($smbios_conf->{base64}) {
3596 # Do not pass base64 flag to qemu
3597 delete $smbios_conf->{base64};
3598 my $smbios_string = "";
3599 foreach my $key (keys %$smbios_conf) {
3600 my $value;
3601 if ($key eq "uuid") {
3602 $value = $smbios_conf->{uuid}
3603 } else {
3604 $value = decode_base64($smbios_conf->{$key});
3605 }
3606 # qemu accepts any binary data, only commas need escaping by double comma
3607 $value =~ s/,/,,/g;
3608 $smbios_string .= "," . $key . "=" . $value if $value;
3609 }
3610 push @$cmd, '-smbios', "type=1" . $smbios_string;
3611 } else {
3612 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3613 }
2796e7d5
DM
3614 }
3615
6ee499ff
DC
3616 if ($conf->{vmgenid}) {
3617 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid};
3618 }
3619
96ed3574 3620 my ($ovmf_code, $ovmf_vars) = get_ovmf_files($arch);
3edb45e7 3621 if ($conf->{bios} && $conf->{bios} eq 'ovmf') {
96ed3574 3622 die "uefi base image not found\n" if ! -f $ovmf_code;
2ddc0a5c 3623
4dcce9ee 3624 my $path;
13bca7b4 3625 my $format;
4dcce9ee
TL
3626 if (my $efidisk = $conf->{efidisk0}) {
3627 my $d = PVE::JSONSchema::parse_property_string($efidisk_fmt, $efidisk);
2ddc0a5c 3628 my ($storeid, $volname) = PVE::Storage::parse_volume_id($d->{file}, 1);
13bca7b4 3629 $format = $d->{format};
2ddc0a5c
DC
3630 if ($storeid) {
3631 $path = PVE::Storage::path($storecfg, $d->{file});
13bca7b4
WB
3632 if (!defined($format)) {
3633 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
3634 $format = qemu_img_format($scfg, $volname);
3635 }
2ddc0a5c
DC
3636 } else {
3637 $path = $d->{file};
13bca7b4
WB
3638 die "efidisk format must be specified\n"
3639 if !defined($format);
2ddc0a5c 3640 }
2ddc0a5c 3641 } else {
4dcce9ee
TL
3642 warn "no efidisk configured! Using temporary efivars disk.\n";
3643 $path = "/tmp/$vmid-ovmf.fd";
96ed3574 3644 PVE::Tools::file_copy($ovmf_vars, $path, -s $ovmf_vars);
13bca7b4 3645 $format = 'raw';
2ddc0a5c 3646 }
4dcce9ee 3647
96ed3574 3648 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
2bfbee03 3649 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
a783c78e
AD
3650 }
3651
7583d156
DC
3652 # load q35 config
3653 if ($q35) {
3654 # we use different pcie-port hardware for qemu >= 4.0 for passthrough
3655 if (qemu_machine_feature_enabled($machine_type, $kvmver, 4, 0)) {
3656 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35-4.0.cfg';
3657 } else {
3658 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
3659 }
3660 }
da8b4189 3661
d40e5e18 3662 # add usb controllers
d559309f 3663 my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers($conf, $bridges, $arch, $machine_type, $usbdesc->{format}, $MAX_USB_DEVICES);
d40e5e18 3664 push @$devices, @usbcontrollers if @usbcontrollers;
55655ebc 3665 my $vga = parse_vga($conf->{vga});
2fa3151e 3666
55655ebc
DC
3667 my $qxlnum = vga_conf_has_spice($conf->{vga});
3668 $vga->{type} = 'qxl' if $qxlnum;
2fa3151e 3669
55655ebc 3670 if (!$vga->{type}) {
869ad4a7
WB
3671 if ($arch eq 'aarch64') {
3672 $vga->{type} = 'virtio';
3673 } elsif (qemu_machine_feature_enabled($machine_type, $kvmver, 2, 9)) {
55655ebc 3674 $vga->{type} = (!$winversion || $winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3675 } else {
55655ebc 3676 $vga->{type} = ($winversion >= 6) ? 'std' : 'cirrus';
a2a5cd64 3677 }
5acbfe9e
DM
3678 }
3679
1e3baf05 3680 # enable absolute mouse coordinates (needed by vnc)
5acbfe9e
DM
3681 my $tablet;
3682 if (defined($conf->{tablet})) {
3683 $tablet = $conf->{tablet};
3684 } else {
3685 $tablet = $defaults->{tablet};
590e698c 3686 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
55655ebc 3687 $tablet = 0 if $vga->{type} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
5acbfe9e
DM
3688 }
3689
d559309f
WB
3690 if ($tablet) {
3691 push @$devices, '-device', print_tabletdevice_full($conf, $arch) if $tablet;
3692 my $kbd = print_keyboarddevice_full($conf, $arch);
3693 push @$devices, '-device', $kbd if defined($kbd);
3694 }
b467f79a 3695
16a91d65 3696 my $kvm_off = 0;
4317f69f
AD
3697 my $gpu_passthrough;
3698
1e3baf05 3699 # host pci devices
040b06b7 3700 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
dae0c8e5
TL
3701 my $id = "hostpci$i";
3702 my $d = parse_hostpci($conf->{$id});
2e3b7e2a
AD
3703 next if !$d;
3704
dae0c8e5 3705 if (my $pcie = $d->{pcie}) {
2e3b7e2a 3706 die "q35 machine model is not enabled" if !$q35;
739ba340
DC
3707 # win7 wants to have the pcie devices directly on the pcie bus
3708 # instead of in the root port
3709 if ($winversion == 7) {
dae0c8e5 3710 $pciaddr = print_pcie_addr("${id}bus0");
739ba340 3711 } else {
c4e16381 3712 # add more root ports if needed, 4 are present by default
dae0c8e5 3713 # by pve-q35 cfgs, rest added here on demand.
c4e16381
AL
3714 if ($i > 3) {
3715 push @$devices, '-device', print_pcie_root_port($i);
3716 }
dae0c8e5 3717 $pciaddr = print_pcie_addr($id);
739ba340 3718 }
bd772c2e 3719 } else {
dae0c8e5 3720 $pciaddr = print_pci_addr($id, $bridges, $arch, $machine_type);
2e3b7e2a
AD
3721 }
3722
1f4f447b
WB
3723 my $xvga = '';
3724 if ($d->{'x-vga'}) {
dae0c8e5 3725 $xvga = ',x-vga=on' if !($conf->{bios} && $conf->{bios} eq 'ovmf');
16a91d65 3726 $kvm_off = 1;
bfc0bb81 3727 $vga->{type} = 'none' if !defined($conf->{vga});
4317f69f 3728 $gpu_passthrough = 1;
137483c0 3729 }
dae0c8e5 3730
4543ecf0
AD
3731 my $pcidevices = $d->{pciid};
3732 my $multifunction = 1 if @$pcidevices > 1;
dae0c8e5 3733
6ab45bd7
DC
3734 my $sysfspath;
3735 if ($d->{mdev} && scalar(@$pcidevices) == 1) {
dae0c8e5 3736 my $pci_id = $pcidevices->[0]->{id};
6ab45bd7 3737 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
dae0c8e5 3738 $sysfspath = "/sys/bus/pci/devices/0000:$pci_id/$uuid";
6ab45bd7 3739 } elsif ($d->{mdev}) {
dae0c8e5 3740 warn "ignoring mediated device '$id' with multifunction device\n";
6ab45bd7 3741 }
2e3b7e2a 3742
4543ecf0 3743 my $j=0;
dae0c8e5 3744 foreach my $pcidevice (@$pcidevices) {
6ab45bd7 3745 my $devicestr = "vfio-pci";
dae0c8e5 3746
6ab45bd7
DC
3747 if ($sysfspath) {
3748 $devicestr .= ",sysfsdev=$sysfspath";
3749 } else {
2fd24788 3750 $devicestr .= ",host=$pcidevice->{id}";
6ab45bd7 3751 }
4543ecf0 3752
dae0c8e5
TL
3753 my $mf_addr = $multifunction ? ".$j" : '';
3754 $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";
3755
3756 if ($j == 0) {
3757 $devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar};
3758 $devicestr .= "$xvga";
4543ecf0 3759 $devicestr .= ",multifunction=on" if $multifunction;
dae0c8e5 3760 $devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile};
4543ecf0
AD
3761 }
3762
3763 push @$devices, '-device', $devicestr;
3764 $j++;
3765 }
1e3baf05
DM
3766 }
3767
3768 # usb devices
ae36393d 3769 my $usb_dev_features = {};
733234be 3770 $usb_dev_features->{spice_usb3} = 1 if qemu_machine_feature_enabled($machine_type, $kvmver, 4, 0);
ae36393d
AL
3771
3772 my @usbdevices = PVE::QemuServer::USB::get_usb_devices($conf, $usbdesc->{format}, $MAX_USB_DEVICES, $usb_dev_features);
d40e5e18 3773 push @$devices, @usbdevices if @usbdevices;
1e3baf05 3774 # serial devices
bae179aa 3775 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
34978be3 3776 if (my $path = $conf->{"serial$i"}) {
9f9d2fb2
DM
3777 if ($path eq 'socket') {
3778 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3779 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
91b01bbb
WB
3780 # On aarch64, serial0 is the UART device. Qemu only allows
3781 # connecting UART devices via the '-serial' command line, as
3782 # the device has a fixed slot on the hardware...
3783 if ($arch eq 'aarch64' && $i == 0) {
3784 push @$devices, '-serial', "chardev:serial$i";
3785 } else {
3786 push @$devices, '-device', "isa-serial,chardev=serial$i";
3787 }
9f9d2fb2
DM
3788 } else {
3789 die "no such serial device\n" if ! -c $path;
3790 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3791 push @$devices, '-device', "isa-serial,chardev=serial$i";
3792 }
34978be3 3793 }
1e3baf05
DM
3794 }
3795
3796 # parallel devices
1989a89c 3797 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
34978be3 3798 if (my $path = $conf->{"parallel$i"}) {
19672434 3799 die "no such parallel device\n" if ! -c $path;
32e69805 3800 my $devtype = $path =~ m!^/dev/usb/lp! ? 'tty' : 'parport';
4c5dbaf6 3801 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
5bdcf937 3802 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
34978be3 3803 }
1e3baf05
DM
3804 }
3805
d5535a00
TL
3806 if (my $audio = conf_has_audio($conf)) {
3807
2e7b5925
AL
3808 my $audiopciaddr = print_pci_addr("audio0", $bridges, $arch, $machine_type);
3809
d5535a00
TL
3810 my $id = $audio->{dev_id};
3811 if ($audio->{dev} eq 'AC97') {
3812 push @$devices, '-device', "AC97,id=${id}${audiopciaddr}";
3813 } elsif ($audio->{dev} =~ /intel\-hda$/) {
3814 push @$devices, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
3815 push @$devices, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0";
3816 push @$devices, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1";
b3703d39 3817 } else {
d5535a00 3818 die "unkown audio device '$audio->{dev}', implement me!";
2e7b5925 3819 }
1448547f 3820
d5535a00 3821 push @$devices, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
2e7b5925 3822 }
19672434 3823
1e3baf05
DM
3824 my $sockets = 1;
3825 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3826 $sockets = $conf->{sockets} if $conf->{sockets};
3827
3828 my $cores = $conf->{cores} || 1;
3bd18e48 3829
de9d1e55 3830 my $maxcpus = $sockets * $cores;
76267728 3831
de9d1e55 3832 my $vcpus = $conf->{vcpus} ? $conf->{vcpus} : $maxcpus;
76267728 3833
de9d1e55
AD
3834 my $allowed_vcpus = $cpuinfo->{cpus};
3835
6965d5d1 3836 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
de9d1e55
AD
3837 if ($allowed_vcpus < $maxcpus);
3838
69c81430 3839 if($hotplug_features->{cpu} && qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 7)) {
1e3baf05 3840
69c81430
AD
3841 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3842 for (my $i = 2; $i <= $vcpus; $i++) {
3843 my $cpustr = print_cpu_device($conf,$i);
3844 push @$cmd, '-device', $cpustr;
3845 }
3846
3847 } else {
3848
3849 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3850 }
1e3baf05
DM
3851 push @$cmd, '-nodefaults';
3852
32baffb4 3853 my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
3b408e82 3854
0888fdce
DM
3855 my $bootindex_hash = {};
3856 my $i = 1;
3857 foreach my $o (split(//, $bootorder)) {
3858 $bootindex_hash->{$o} = $i*100;
3859 $i++;
afdb31d5 3860 }
3b408e82 3861
dbea4415 3862 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
1e3baf05 3863
6b64503e 3864 push @$cmd, '-no-acpi' if defined($conf->{acpi}) && $conf->{acpi} == 0;
1e3baf05 3865
6b64503e 3866 push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
1e3baf05 3867
84902837 3868 if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none'){
d559309f 3869 push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
b7be4ba9 3870 my $socket = vnc_socket($vmid);
dc62a7fa 3871 push @$cmd, '-vnc', "unix:$socket,password";
b7be4ba9 3872 } else {
55655ebc 3873 push @$cmd, '-vga', 'none' if $vga->{type} eq 'none';
b7be4ba9
AD
3874 push @$cmd, '-nographic';
3875 }
3876
1e3baf05 3877 # time drift fix
6b64503e 3878 my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
1e3baf05 3879
8c559505 3880 my $useLocaltime = $conf->{localtime};
1e3baf05 3881
4317f69f
AD
3882 if ($winversion >= 5) { # windows
3883 $useLocaltime = 1 if !defined($conf->{localtime});
7a131888 3884
4317f69f
AD
3885 # use time drift fix when acpi is enabled
3886 if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) {
3887 $tdf = 1 if !defined($conf->{tdf});
462e8d19 3888 }
4317f69f 3889 }
462e8d19 3890
4317f69f
AD
3891 if ($winversion >= 6) {
3892 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3893 push @$cmd, '-no-hpet';
1e3baf05
DM
3894 }
3895
8c559505
DM
3896 push @$rtcFlags, 'driftfix=slew' if $tdf;
3897
74c02ef7 3898 if (!$kvm) {
8c559505 3899 push @$machineFlags, 'accel=tcg';
7f0b5beb 3900 }
1e3baf05 3901
952958bc
DM
3902 if ($machine_type) {
3903 push @$machineFlags, "type=${machine_type}";
3bafc510
DM
3904 }
3905
85f0511d 3906 if (($conf->{startdate}) && ($conf->{startdate} ne 'now')) {
8c559505
DM
3907 push @$rtcFlags, "base=$conf->{startdate}";
3908 } elsif ($useLocaltime) {
3909 push @$rtcFlags, 'base=localtime';
3910 }
1e3baf05 3911
4fc262bd 3912 push @$cmd, get_cpu_options($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
519ed28c 3913
0567a4d5 3914 PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
370b05e7 3915
1e3baf05
DM
3916 push @$cmd, '-S' if $conf->{freeze};
3917
b20df606 3918 push @$cmd, '-k', $conf->{keyboard} if defined($conf->{keyboard});
1e3baf05 3919
9d66b397 3920 if (parse_guest_agent($conf)->{enabled}) {
7a6c2150 3921 my $qgasocket = qmp_socket($vmid, 1);
d559309f 3922 my $pciaddr = print_pci_addr("qga0", $bridges, $arch, $machine_type);
ab6a046f
AD
3923 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3924 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3925 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3926 }
3927
1d794448 3928 my $spice_port;
2fa3151e 3929
590e698c
DM
3930 if ($qxlnum) {
3931 if ($qxlnum > 1) {
ac087616 3932 if ($winversion){
590e698c 3933 for(my $i = 1; $i < $qxlnum; $i++){
d559309f 3934 push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
590e698c
DM
3935 }
3936 } else {
3937 # assume other OS works like Linux
55655ebc
DC
3938 my ($ram, $vram) = ("134217728", "67108864");
3939 if ($vga->{memory}) {
3940 $ram = PVE::Tools::convert_size($qxlnum*4*$vga->{memory}, 'mb' => 'b');
3941 $vram = PVE::Tools::convert_size($qxlnum*2*$vga->{memory}, 'mb' => 'b');
3942 }
3943 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3944 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
2fa3151e
AD
3945 }
3946 }
3947
d559309f 3948 my $pciaddr = print_pci_addr("spice", $bridges, $arch, $machine_type);
95a4b4a9 3949
af0eba7e
WB
3950 my $nodename = PVE::INotify::nodename();
3951 my $pfamily = PVE::Tools::get_host_address_family($nodename);
91152441
WB
3952 my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily);
3953 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
4d316a63
AL
3954
3955 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3956 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3957 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3958
91152441
WB
3959 my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
3960 $spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
943340a6 3961
caab114a
TL
3962 my $spice_enhancement = PVE::JSONSchema::parse_property_string($spice_enhancements_fmt, $conf->{spice_enhancements} // '');
3963 if ($spice_enhancement->{foldersharing}) {
3964 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
3965 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
3966 }
c4df18db 3967
caab114a
TL
3968 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3969 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}" if $spice_enhancement->{videostreaming};
3970 push @$devices, '-spice', "$spice_opts";
1011b570
DM
3971 }
3972
8d9ae0d2
DM
3973 # enable balloon by default, unless explicitly disabled
3974 if (!defined($conf->{balloon}) || $conf->{balloon}) {
d559309f 3975 $pciaddr = print_pci_addr("balloon0", $bridges, $arch, $machine_type);
8d9ae0d2
DM
3976 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3977 }
1e3baf05 3978
0ea9541d
DM
3979 if ($conf->{watchdog}) {
3980 my $wdopts = parse_watchdog($conf->{watchdog});
d559309f 3981 $pciaddr = print_pci_addr("watchdog", $bridges, $arch, $machine_type);
0a40e8ea 3982 my $watchdog = $wdopts->{model} || 'i6300esb';
5bdcf937
AD
3983 push @$devices, '-device', "$watchdog$pciaddr";
3984 push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
0ea9541d
DM
3985 }
3986
1e3baf05 3987 my $vollist = [];
941e0c42 3988 my $scsicontroller = {};
26ee04b6 3989 my $ahcicontroller = {};
cdd20088 3990 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : $defaults->{scsihw};
1e3baf05 3991
5881b913
DM
3992 # Add iscsi initiator name if available
3993 if (my $initiator = get_initiator_name()) {
3994 push @$devices, '-iscsi', "initiator-name=$initiator";
3995 }
3996
1e3baf05
DM
3997 foreach_drive($conf, sub {
3998 my ($ds, $drive) = @_;
3999
ff1a2432 4000 if (PVE::Storage::parse_volume_id($drive->{file}, 1)) {
1e3baf05 4001 push @$vollist, $drive->{file};
ff1a2432 4002 }
afdb31d5 4003
4dcce9ee
TL
4004 # ignore efidisk here, already added in bios/fw handling code above
4005 return if $drive->{interface} eq 'efidisk';
4006
1e3baf05 4007 $use_virtio = 1 if $ds =~ m/^virtio/;
3b408e82
DM
4008
4009 if (drive_is_cdrom ($drive)) {
4010 if ($bootindex_hash->{d}) {
4011 $drive->{bootindex} = $bootindex_hash->{d};
4012 $bootindex_hash->{d} += 1;
4013 }
4014 } else {
4015 if ($bootindex_hash->{c}) {
4016 $drive->{bootindex} = $bootindex_hash->{c} if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds);
4017 $bootindex_hash->{c} += 1;
4018 }
4019 }
4020
51f492cd
AD
4021 if($drive->{interface} eq 'virtio'){
4022 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread};
4023 }
4024
941e0c42 4025 if ($drive->{interface} eq 'scsi') {
cdd20088 4026
ee034f5c 4027 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
6731a4cf 4028
d559309f 4029 $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $machine_type);
a1b7d579 4030 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
fc8b40fd
AD
4031
4032 my $iothread = '';
4033 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{iothread}){
4034 $iothread .= ",iothread=iothread-$controller_prefix$controller";
4035 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
e7a5104d
DC
4036 } elsif ($drive->{iothread}) {
4037 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
fc8b40fd
AD
4038 }
4039
6e11f143
AD
4040 my $queues = '';
4041 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{queues}){
4042 $queues = ",num_queues=$drive->{queues}";
370b05e7 4043 }
6e11f143
AD
4044
4045 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
cdd20088 4046 $scsicontroller->{$controller}=1;
941e0c42 4047 }
3b408e82 4048
26ee04b6
DA
4049 if ($drive->{interface} eq 'sata') {
4050 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
d559309f 4051 $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
5bdcf937 4052 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
26ee04b6
DA
4053 $ahcicontroller->{$controller}=1;
4054 }
46f58b5f 4055
15b21acc
MR
4056 my $drive_cmd = print_drive_full($storecfg, $vmid, $drive);
4057 push @$devices, '-drive',$drive_cmd;
d559309f 4058 push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
1e3baf05
DM
4059 });
4060
cc4d6182 4061 for (my $i = 0; $i < $MAX_NETS; $i++) {
5f0c4c32 4062 next if !$conf->{"net$i"};
cc4d6182
DA
4063 my $d = parse_net($conf->{"net$i"});
4064 next if !$d;
1e3baf05 4065
cc4d6182 4066 $use_virtio = 1 if $d->{model} eq 'virtio';
1e3baf05 4067
cc4d6182
DA
4068 if ($bootindex_hash->{n}) {
4069 $d->{bootindex} = $bootindex_hash->{n};
4070 $bootindex_hash->{n} += 1;
4071 }
1e3baf05 4072
d559309f 4073 my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, "net$i");
5bdcf937
AD
4074 push @$devices, '-netdev', $netdevfull;
4075
d559309f 4076 my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
5bdcf937
AD
4077 push @$devices, '-device', $netdevicefull;
4078 }
1e3baf05 4079
6dbcb073
DC
4080 if ($conf->{ivshmem}) {
4081 my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
e3c27a6a 4082
6dbcb073
DC
4083 my $bus;
4084 if ($q35) {
4085 $bus = print_pcie_addr("ivshmem");
4086 } else {
4087 $bus = print_pci_addr("ivshmem", $bridges, $arch, $machine_type);
4088 }
e3c27a6a
TL
4089
4090 my $ivshmem_name = $ivshmem->{name} // $vmid;
4091 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
4092
6dbcb073
DC
4093 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
4094 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
4095 }
4096
db656e5f
DM
4097 if (!$q35) {
4098 # add pci bridges
fc79e813
AD
4099 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
4100 $bridges->{1} = 1;
4101 $bridges->{2} = 1;
4102 }
4103
6731a4cf
AD
4104 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
4105
311e9293 4106 for my $k (sort {$b cmp $a} keys %$bridges) {
d559309f 4107 $pciaddr = print_pci_addr("pci.$k", undef, $arch, $machine_type);
f8e83f05
AD
4108 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
4109 }
19672434
DM
4110 }
4111
5bdcf937 4112 push @$cmd, @$devices;
be190583 4113 push @$cmd, '-rtc', join(',', @$rtcFlags)
8c559505 4114 if scalar(@$rtcFlags);
be190583 4115 push @$cmd, '-machine', join(',', @$machineFlags)
8c559505
DM
4116 if scalar(@$machineFlags);
4117 push @$cmd, '-global', join(',', @$globalFlags)
4118 if scalar(@$globalFlags);
4119
7ceade4c
DC
4120 if (my $vmstate = $conf->{vmstate}) {
4121 my $statepath = PVE::Storage::path($storecfg, $vmstate);
24d1f93a 4122 push @$vollist, $vmstate;
7ceade4c
DC
4123 push @$cmd, '-loadstate', $statepath;
4124 }
4125
76350670
DC
4126 # add custom args
4127 if ($conf->{args}) {
4128 my $aa = PVE::Tools::split_args($conf->{args});
4129 push @$cmd, @$aa;
4130 }
4131
1d794448 4132 return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
1e3baf05 4133}
19672434 4134
1e3baf05
DM
4135sub vnc_socket {
4136 my ($vmid) = @_;
4137 return "${var_run_tmpdir}/$vmid.vnc";
4138}
4139
943340a6 4140sub spice_port {
1011b570 4141 my ($vmid) = @_;
943340a6 4142
1d794448 4143 my $res = vm_mon_cmd($vmid, 'query-spice');
943340a6
DM
4144
4145 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
1011b570
DM
4146}
4147
c971c4f2 4148sub qmp_socket {
71bd73b5 4149 my ($vmid, $qga, $name) = @_;
693d12a2 4150 my $sockettype = $qga ? 'qga' : 'qmp';
71bd73b5
DC
4151 my $ext = $name ? '-'.$name : '';
4152 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
c971c4f2
AD
4153}
4154
1e3baf05
DM
4155sub pidfile_name {
4156 my ($vmid) = @_;
4157 return "${var_run_tmpdir}/$vmid.pid";
4158}
4159
86fdcfb2
DA
4160sub vm_devices_list {
4161 my ($vmid) = @_;
4162
ceea9078 4163 my $res = vm_mon_cmd($vmid, 'query-pci');
f721624b 4164 my $devices_to_check = [];
ceea9078
DM
4165 my $devices = {};
4166 foreach my $pcibus (@$res) {
f721624b
DC
4167 push @$devices_to_check, @{$pcibus->{devices}},
4168 }
4169
4170 while (@$devices_to_check) {
4171 my $to_check = [];
4172 for my $d (@$devices_to_check) {
4173 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4174 next if !$d->{'pci_bridge'};
4175
4176 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices}});
4177 push @$to_check, @{$d->{'pci_bridge'}->{devices}};
f78cc802 4178 }
f721624b 4179 $devices_to_check = $to_check;
f78cc802
AD
4180 }
4181
4182 my $resblock = vm_mon_cmd($vmid, 'query-block');
4183 foreach my $block (@$resblock) {
4184 if($block->{device} =~ m/^drive-(\S+)/){
4185 $devices->{$1} = 1;
1dc4f496
DM
4186 }
4187 }
86fdcfb2 4188
3d7389fe
DM
4189 my $resmice = vm_mon_cmd($vmid, 'query-mice');
4190 foreach my $mice (@$resmice) {
4191 if ($mice->{name} eq 'QEMU HID Tablet') {
4192 $devices->{tablet} = 1;
4193 last;
4194 }
4195 }
4196
deb091c5
DC
4197 # for usb devices there is no query-usb
4198 # but we can iterate over the entries in
4199 # qom-list path=/machine/peripheral
4200 my $resperipheral = vm_mon_cmd($vmid, 'qom-list', path => '/machine/peripheral');
4201 foreach my $per (@$resperipheral) {
4202 if ($per->{name} =~ m/^usb\d+$/) {
4203 $devices->{$per->{name}} = 1;
4204 }
4205 }
4206
1dc4f496 4207 return $devices;
86fdcfb2
DA
4208}
4209
ec21aa11 4210sub vm_deviceplug {
d559309f 4211 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
ae57f6b3 4212
db656e5f
DM
4213 my $q35 = machine_type_is_q35($conf);
4214
95d6343b
DA
4215 my $devices_list = vm_devices_list($vmid);
4216 return 1 if defined($devices_list->{$deviceid});
4217
d559309f 4218 qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
fee46675 4219
3d7389fe 4220 if ($deviceid eq 'tablet') {
fee46675 4221
d559309f
WB
4222 qemu_deviceadd($vmid, print_tabletdevice_full($conf, $arch));
4223
4224 } elsif ($deviceid eq 'keyboard') {
4225
4226 qemu_deviceadd($vmid, print_keyboarddevice_full($conf, $arch));
3d7389fe 4227
4eb68604
DC
4228 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4229
f745762b
DC
4230 die "usb hotplug currently not reliable\n";
4231 # since we can't reliably hot unplug all added usb devices
4232 # and usb passthrough disables live migration
4233 # we disable usb hotplugging for now
4eb68604
DC
4234 qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
4235
fee46675 4236 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
40f28a9f 4237
22de899a
AD
4238 qemu_iothread_add($vmid, $deviceid, $device);
4239
fee46675 4240 qemu_driveadd($storecfg, $vmid, $device);
d559309f 4241 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $machine_type);
fee46675 4242
5e5dcb73 4243 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
4244 eval { qemu_deviceaddverify($vmid, $deviceid); };
4245 if (my $err = $@) {
63c2da2f
DM
4246 eval { qemu_drivedel($vmid, $deviceid); };
4247 warn $@ if $@;
fee46675 4248 die $err;
5e5dcb73 4249 }
cfc817c7 4250
2733141c 4251 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
fee46675 4252
fc8b40fd 4253
cdd20088 4254 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
d559309f 4255 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
a1b7d579 4256 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
2733141c
AD
4257
4258 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
fee46675 4259
fc8b40fd
AD
4260 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread}) {
4261 qemu_iothread_add($vmid, $deviceid, $device);
4262 $devicefull .= ",iothread=iothread-$deviceid";
4263 }
4264
6e11f143
AD
4265 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues}) {
4266 $devicefull .= ",num_queues=$device->{queues}";
4267 }
4268
cfc817c7 4269 qemu_deviceadd($vmid, $devicefull);
fee46675 4270 qemu_deviceaddverify($vmid, $deviceid);
cfc817c7 4271
fee46675
DM
4272 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4273
d559309f 4274 qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device, $arch, $machine_type);
fee46675 4275 qemu_driveadd($storecfg, $vmid, $device);
a1b7d579 4276
d559309f 4277 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $machine_type);
fee46675
DM
4278 eval { qemu_deviceadd($vmid, $devicefull); };
4279 if (my $err = $@) {
63c2da2f
DM
4280 eval { qemu_drivedel($vmid, $deviceid); };
4281 warn $@ if $@;
fee46675 4282 die $err;
a4f091a0 4283 }
a4f091a0 4284
fee46675
DM
4285 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4286
95d3be58 4287 return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
8718099c 4288
95d3be58
DC
4289 my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
4290 my $use_old_bios_files = undef;
4291 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
8718099c 4292
95d3be58
DC
4293 my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4294 qemu_deviceadd($vmid, $netdevicefull);
79046fd1
DC
4295 eval {
4296 qemu_deviceaddverify($vmid, $deviceid);
4297 qemu_set_link_status($vmid, $deviceid, !$device->{link_down});
4298 };
fee46675
DM
4299 if (my $err = $@) {
4300 eval { qemu_netdevdel($vmid, $deviceid); };
4301 warn $@ if $@;
4302 die $err;
95d3be58 4303 }
2630d2a9 4304
fee46675 4305 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
b467f79a 4306
40f28a9f 4307 my $bridgeid = $2;
d559309f 4308 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
40f28a9f 4309 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
a1b7d579 4310
40f28a9f 4311 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
4312 qemu_deviceaddverify($vmid, $deviceid);
4313
4314 } else {
a1b7d579 4315 die "can't hotplug device '$deviceid'\n";
40f28a9f
AD
4316 }
4317
5e5dcb73 4318 return 1;
a4dea331
DA
4319}
4320
3eec5767 4321# fixme: this should raise exceptions on error!
ec21aa11 4322sub vm_deviceunplug {
f19d1c47 4323 my ($vmid, $conf, $deviceid) = @_;
873c2d69 4324
95d6343b
DA
4325 my $devices_list = vm_devices_list($vmid);
4326 return 1 if !defined($devices_list->{$deviceid});
4327
63c2da2f
DM
4328 die "can't unplug bootdisk" if $conf->{bootdisk} && $conf->{bootdisk} eq $deviceid;
4329
d559309f 4330 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
63c2da2f 4331
3d7389fe 4332 qemu_devicedel($vmid, $deviceid);
3d7389fe 4333
4eb68604
DC
4334 } elsif ($deviceid =~ m/^usb\d+$/) {
4335
f745762b
DC
4336 die "usb hotplug currently not reliable\n";
4337 # when unplugging usb devices this way,
4338 # there may be remaining usb controllers/hubs
4339 # so we disable it for now
4eb68604
DC
4340 qemu_devicedel($vmid, $deviceid);
4341 qemu_devicedelverify($vmid, $deviceid);
4342
63c2da2f 4343 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
f19d1c47 4344
5e5dcb73 4345 qemu_devicedel($vmid, $deviceid);
63c2da2f
DM
4346 qemu_devicedelverify($vmid, $deviceid);
4347 qemu_drivedel($vmid, $deviceid);
22de899a
AD
4348 qemu_iothread_del($conf, $vmid, $deviceid);
4349
2733141c 4350 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
a1b7d579 4351
63c2da2f 4352 qemu_devicedel($vmid, $deviceid);
8ce30dde 4353 qemu_devicedelverify($vmid, $deviceid);
fc8b40fd 4354 qemu_iothread_del($conf, $vmid, $deviceid);
a1b7d579 4355
63c2da2f 4356 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
cfc817c7 4357
63c2da2f
DM
4358 qemu_devicedel($vmid, $deviceid);
4359 qemu_drivedel($vmid, $deviceid);
a1b7d579 4360 qemu_deletescsihw($conf, $vmid, $deviceid);
8ce30dde 4361
63c2da2f 4362 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
a4f091a0 4363
2630d2a9 4364 qemu_devicedel($vmid, $deviceid);
63c2da2f
DM
4365 qemu_devicedelverify($vmid, $deviceid);
4366 qemu_netdevdel($vmid, $deviceid);
4367
4368 } else {
4369 die "can't unplug device '$deviceid'\n";
2630d2a9
DA
4370 }
4371
5e5dcb73
DA
4372 return 1;
4373}
4374
4375sub qemu_deviceadd {
4376 my ($vmid, $devicefull) = @_;
873c2d69 4377
d695b5b7
AD
4378 $devicefull = "driver=".$devicefull;
4379 my %options = split(/[=,]/, $devicefull);
f19d1c47 4380
d695b5b7 4381 vm_mon_cmd($vmid, "device_add" , %options);
5e5dcb73 4382}
afdb31d5 4383
5e5dcb73 4384sub qemu_devicedel {
fee46675 4385 my ($vmid, $deviceid) = @_;
63c2da2f 4386
5a77d8c1 4387 my $ret = vm_mon_cmd($vmid, "device_del", id => $deviceid);
5e5dcb73
DA
4388}
4389
22de899a
AD
4390sub qemu_iothread_add {
4391 my($vmid, $deviceid, $device) = @_;
4392
4393 if ($device->{iothread}) {
4394 my $iothreads = vm_iothreads_list($vmid);
4395 qemu_objectadd($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4396 }
4397}
4398
4399sub qemu_iothread_del {
4400 my($conf, $vmid, $deviceid) = @_;
4401
7820eae4
DC
4402 my $confid = $deviceid;
4403 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
4404 $confid = 'scsi' . $1;
4405 }
4406 my $device = parse_drive($confid, $conf->{$confid});
22de899a
AD
4407 if ($device->{iothread}) {
4408 my $iothreads = vm_iothreads_list($vmid);
4409 qemu_objectdel($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4410 }
4411}
4412
4d3f29ed
AD
4413sub qemu_objectadd {
4414 my($vmid, $objectid, $qomtype) = @_;
4415
4416 vm_mon_cmd($vmid, "object-add", id => $objectid, "qom-type" => $qomtype);
4417
4418 return 1;
4419}
4420
4421sub qemu_objectdel {
4422 my($vmid, $objectid) = @_;
4423
4424 vm_mon_cmd($vmid, "object-del", id => $objectid);
4425
4426 return 1;
4427}
4428
5e5dcb73 4429sub qemu_driveadd {
fee46675 4430 my ($storecfg, $vmid, $device) = @_;
5e5dcb73
DA
4431
4432 my $drive = print_drive_full($storecfg, $vmid, $device);
7a69fc3c 4433 $drive =~ s/\\/\\\\/g;
8ead5ec7 4434 my $ret = vm_human_monitor_command($vmid, "drive_add auto \"$drive\"");
fee46675 4435
5e5dcb73 4436 # If the command succeeds qemu prints: "OK"
fee46675
DM
4437 return 1 if $ret =~ m/OK/s;
4438
4439 die "adding drive failed: $ret\n";
5e5dcb73 4440}
afdb31d5 4441
5e5dcb73
DA
4442sub qemu_drivedel {
4443 my($vmid, $deviceid) = @_;
873c2d69 4444
7b7c6d1b 4445 my $ret = vm_human_monitor_command($vmid, "drive_del drive-$deviceid");
5e5dcb73 4446 $ret =~ s/^\s+//;
a1b7d579 4447
63c2da2f 4448 return 1 if $ret eq "";
a1b7d579 4449
63c2da2f 4450 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
a1b7d579
DM
4451 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4452
63c2da2f 4453 die "deleting drive $deviceid failed : $ret\n";
5e5dcb73 4454}
f19d1c47 4455
5e5dcb73 4456sub qemu_deviceaddverify {
fee46675 4457 my ($vmid, $deviceid) = @_;
873c2d69 4458
5e5dcb73
DA
4459 for (my $i = 0; $i <= 5; $i++) {
4460 my $devices_list = vm_devices_list($vmid);
4461 return 1 if defined($devices_list->{$deviceid});
4462 sleep 1;
afdb31d5 4463 }
fee46675
DM
4464
4465 die "error on hotplug device '$deviceid'\n";
5e5dcb73 4466}
afdb31d5 4467
5e5dcb73
DA
4468
4469sub qemu_devicedelverify {
63c2da2f
DM
4470 my ($vmid, $deviceid) = @_;
4471
a1b7d579 4472 # need to verify that the device is correctly removed as device_del
63c2da2f 4473 # is async and empty return is not reliable
5e5dcb73 4474
5e5dcb73
DA
4475 for (my $i = 0; $i <= 5; $i++) {
4476 my $devices_list = vm_devices_list($vmid);
4477 return 1 if !defined($devices_list->{$deviceid});
4478 sleep 1;
afdb31d5 4479 }
63c2da2f
DM
4480
4481 die "error on hot-unplugging device '$deviceid'\n";
873c2d69
DA
4482}
4483
cdd20088 4484sub qemu_findorcreatescsihw {
d559309f 4485 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
cfc817c7 4486
ee034f5c 4487 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
2733141c
AD
4488
4489 my $scsihwid="$controller_prefix$controller";
cfc817c7
DA
4490 my $devices_list = vm_devices_list($vmid);
4491
cdd20088 4492 if(!defined($devices_list->{$scsihwid})) {
d559309f 4493 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
cfc817c7 4494 }
fee46675 4495
cfc817c7
DA
4496 return 1;
4497}
4498
8ce30dde
AD
4499sub qemu_deletescsihw {
4500 my ($conf, $vmid, $opt) = @_;
4501
4502 my $device = parse_drive($opt, $conf->{$opt});
4503
a1511b3c 4504 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
2733141c
AD
4505 vm_deviceunplug($vmid, $conf, "virtioscsi$device->{index}");
4506 return 1;
4507 }
4508
ee034f5c 4509 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
8ce30dde
AD
4510
4511 my $devices_list = vm_devices_list($vmid);
4512 foreach my $opt (keys %{$devices_list}) {
74479ee9 4513 if (PVE::QemuServer::is_valid_drivename($opt)) {
8ce30dde
AD
4514 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4515 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4516 return 1;
4517 }
4518 }
4519 }
4520
4521 my $scsihwid="scsihw$controller";
4522
4523 vm_deviceunplug($vmid, $conf, $scsihwid);
4524
4525 return 1;
4526}
4527
281fedb3 4528sub qemu_add_pci_bridge {
d559309f 4529 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
40f28a9f
AD
4530
4531 my $bridges = {};
281fedb3
DM
4532
4533 my $bridgeid;
4534
d559309f 4535 print_pci_addr($device, $bridges, $arch, $machine_type);
40f28a9f
AD
4536
4537 while (my ($k, $v) = each %$bridges) {
4538 $bridgeid = $k;
4539 }
fee46675 4540 return 1 if !defined($bridgeid) || $bridgeid < 1;
281fedb3 4541
40f28a9f
AD
4542 my $bridge = "pci.$bridgeid";
4543 my $devices_list = vm_devices_list($vmid);
4544
281fedb3 4545 if (!defined($devices_list->{$bridge})) {
d559309f 4546 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
40f28a9f 4547 }
281fedb3 4548
40f28a9f
AD
4549 return 1;
4550}
4551
25088687
DM
4552sub qemu_set_link_status {
4553 my ($vmid, $device, $up) = @_;
4554
a1b7d579 4555 vm_mon_cmd($vmid, "set_link", name => $device,
25088687
DM
4556 up => $up ? JSON::true : JSON::false);
4557}
4558
2630d2a9 4559sub qemu_netdevadd {
d559309f 4560 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
2630d2a9 4561
d559309f 4562 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
73aa03b8 4563 my %options = split(/[=,]/, $netdev);
2630d2a9 4564
73aa03b8
AD
4565 vm_mon_cmd($vmid, "netdev_add", %options);
4566 return 1;
2630d2a9
DA
4567}
4568
4569sub qemu_netdevdel {
4570 my ($vmid, $deviceid) = @_;
4571
89c1e0f4 4572 vm_mon_cmd($vmid, "netdev_del", id => $deviceid);
2630d2a9
DA
4573}
4574
16521d63 4575sub qemu_usb_hotplug {
d559309f 4576 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
16521d63
DC
4577
4578 return if !$device;
4579
4580 # remove the old one first
4581 vm_deviceunplug($vmid, $conf, $deviceid);
4582
4583 # check if xhci controller is necessary and available
4584 if ($device->{usb3}) {
4585
4586 my $devicelist = vm_devices_list($vmid);
4587
4588 if (!$devicelist->{xhci}) {
d559309f 4589 my $pciaddr = print_pci_addr("xhci", undef, $arch, $machine_type);
16521d63
DC
4590 qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
4591 }
4592 }
4593 my $d = parse_usb_device($device->{host});
4594 $d->{usb3} = $device->{usb3};
4595
4596 # add the new one
d559309f 4597 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
16521d63
DC
4598}
4599
838776ab 4600sub qemu_cpu_hotplug {
8edc9c08 4601 my ($vmid, $conf, $vcpus) = @_;
838776ab 4602
1e881b75
AD
4603 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4604
8edc9c08
AD
4605 my $sockets = 1;
4606 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4607 $sockets = $conf->{sockets} if $conf->{sockets};
4608 my $cores = $conf->{cores} || 1;
4609 my $maxcpus = $sockets * $cores;
838776ab 4610
8edc9c08 4611 $vcpus = $maxcpus if !$vcpus;
3a11fadb 4612
8edc9c08
AD
4613 die "you can't add more vcpus than maxcpus\n"
4614 if $vcpus > $maxcpus;
3a11fadb 4615
8edc9c08 4616 my $currentvcpus = $conf->{vcpus} || $maxcpus;
1e881b75 4617
eba3e64d 4618 if ($vcpus < $currentvcpus) {
1e881b75
AD
4619
4620 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4621
4622 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4623 qemu_devicedel($vmid, "cpu$i");
4624 my $retry = 0;
4625 my $currentrunningvcpus = undef;
4626 while (1) {
4627 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4628 last if scalar(@{$currentrunningvcpus}) == $i-1;
961af8a3 4629 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
1e881b75
AD
4630 $retry++;
4631 sleep 1;
4632 }
4633 #update conf after each succesfull cpu unplug
4634 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4635 PVE::QemuConfig->write_config($vmid, $conf);
4636 }
4637 } else {
961af8a3 4638 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
1e881b75
AD
4639 }
4640
4641 return;
4642 }
838776ab 4643
8edc9c08 4644 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
961af8a3 4645 die "vcpus in running vm does not match its configuration\n"
8edc9c08 4646 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
838776ab 4647
eba3e64d
AD
4648 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4649
4650 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4651 my $cpustr = print_cpu_device($conf, $i);
4652 qemu_deviceadd($vmid, $cpustr);
4653
4654 my $retry = 0;
4655 my $currentrunningvcpus = undef;
4656 while (1) {
4657 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4658 last if scalar(@{$currentrunningvcpus}) == $i;
961af8a3 4659 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
eba3e64d
AD
4660 sleep 1;
4661 $retry++;
4662 }
4663 #update conf after each succesfull cpu hotplug
4664 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4665 PVE::QemuConfig->write_config($vmid, $conf);
4666 }
4667 } else {
4668
4669 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4670 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4671 }
838776ab
AD
4672 }
4673}
4674
affd2f88 4675sub qemu_block_set_io_throttle {
277ca170
WB
4676 my ($vmid, $deviceid,
4677 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
9196a8ec
WB
4678 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4679 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4680 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
affd2f88 4681
f3f323a3
AD
4682 return if !check_running($vmid) ;
4683
277ca170
WB
4684 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4685 bps => int($bps),
4686 bps_rd => int($bps_rd),
4687 bps_wr => int($bps_wr),
4688 iops => int($iops),
4689 iops_rd => int($iops_rd),
4690 iops_wr => int($iops_wr),
4691 bps_max => int($bps_max),
4692 bps_rd_max => int($bps_rd_max),
4693 bps_wr_max => int($bps_wr_max),
4694 iops_max => int($iops_max),
4695 iops_rd_max => int($iops_rd_max),
9196a8ec
WB
4696 iops_wr_max => int($iops_wr_max),
4697 bps_max_length => int($bps_max_length),
4698 bps_rd_max_length => int($bps_rd_max_length),
4699 bps_wr_max_length => int($bps_wr_max_length),
4700 iops_max_length => int($iops_max_length),
4701 iops_rd_max_length => int($iops_rd_max_length),
4702 iops_wr_max_length => int($iops_wr_max_length),
277ca170 4703 );
f3f323a3 4704
affd2f88
AD
4705}
4706
f5eb281a 4707# old code, only used to shutdown old VM after update
dab36e1e
DM
4708sub __read_avail {
4709 my ($fh, $timeout) = @_;
4710
4711 my $sel = new IO::Select;
4712 $sel->add($fh);
4713
4714 my $res = '';
4715 my $buf;
4716
4717 my @ready;
4718 while (scalar (@ready = $sel->can_read($timeout))) {
4719 my $count;
4720 if ($count = $fh->sysread($buf, 8192)) {
4721 if ($buf =~ /^(.*)\(qemu\) $/s) {
4722 $res .= $1;
4723 last;
4724 } else {
4725 $res .= $buf;
4726 }
4727 } else {
4728 if (!defined($count)) {
4729 die "$!\n";
4730 }
4731 last;
4732 }
4733 }
4734
4735 die "monitor read timeout\n" if !scalar(@ready);
f5eb281a 4736
dab36e1e
DM
4737 return $res;
4738}
4739
c1175c92
AD
4740sub qemu_block_resize {
4741 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4742
ed221350 4743 my $running = check_running($vmid);
c1175c92 4744
7246e8f9 4745 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
c1175c92
AD
4746
4747 return if !$running;
4748
4749 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4750
4751}
4752
1ab0057c
AD
4753sub qemu_volume_snapshot {
4754 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4755
ed221350 4756 my $running = check_running($vmid);
1ab0057c 4757
e5eaa028 4758 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
eba2b721 4759 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync', device => $deviceid, name => $snap);
e5eaa028
WL
4760 } else {
4761 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4762 }
1ab0057c
AD
4763}
4764
fc46aff9
AD
4765sub qemu_volume_snapshot_delete {
4766 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4767
ed221350 4768 my $running = check_running($vmid);
fc46aff9 4769
a2f1554b
AD
4770 if($running) {
4771
4772 $running = undef;
4773 my $conf = PVE::QemuConfig->load_config($vmid);
4774 foreach_drive($conf, sub {
4775 my ($ds, $drive) = @_;
4776 $running = 1 if $drive->{file} eq $volid;
4777 });
4778 }
4779
1ef7592f 4780 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
eba2b721 4781 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync', device => $deviceid, name => $snap);
1ef7592f
AD
4782 } else {
4783 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4784 }
fc46aff9
AD
4785}
4786
264e519f
DM
4787sub set_migration_caps {
4788 my ($vmid) = @_;
a89fded1 4789
8b8345f3 4790 my $cap_ref = [];
a89fded1
AD
4791
4792 my $enabled_cap = {
8b8345f3 4793 "auto-converge" => 1,
0b0a47e8 4794 "xbzrle" => 1,
8b8345f3
DM
4795 "x-rdma-pin-all" => 0,
4796 "zero-blocks" => 0,
b62532e4 4797 "compress" => 0
a89fded1
AD
4798 };
4799
8b8345f3 4800 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
a89fded1 4801
8b8345f3 4802 for my $supported_capability (@$supported_capabilities) {
b463a3ce
SP
4803 push @$cap_ref, {
4804 capability => $supported_capability->{capability},
22430fa2
DM
4805 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4806 };
a89fded1
AD
4807 }
4808
8b8345f3
DM
4809 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4810}
a89fded1 4811
81d95ae1 4812my $fast_plug_option = {
7498eb64 4813 'lock' => 1,
81d95ae1 4814 'name' => 1,
a1b7d579 4815 'onboot' => 1,
81d95ae1
DM
4816 'shares' => 1,
4817 'startup' => 1,
b0ec896e 4818 'description' => 1,
ec647db4 4819 'protection' => 1,
8cad5e9b 4820 'vmstatestorage' => 1,
9e784b11 4821 'hookscript' => 1,
81d95ae1
DM
4822};
4823
3a11fadb
DM
4824# hotplug changes in [PENDING]
4825# $selection hash can be used to only apply specified options, for
4826# example: { cores => 1 } (only apply changed 'cores')
4827# $errors ref is used to return error messages
c427973b 4828sub vmconfig_hotplug_pending {
3a11fadb 4829 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
c427973b 4830
8e90138a 4831 my $defaults = load_defaults();
d559309f 4832 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
c427973b
DM
4833
4834 # commit values which do not have any impact on running VM first
3a11fadb
DM
4835 # Note: those option cannot raise errors, we we do not care about
4836 # $selection and always apply them.
4837
4838 my $add_error = sub {
4839 my ($opt, $msg) = @_;
4840 $errors->{$opt} = "hotplug problem - $msg";
4841 };
c427973b
DM
4842
4843 my $changes = 0;
4844 foreach my $opt (keys %{$conf->{pending}}) { # add/change
81d95ae1 4845 if ($fast_plug_option->{$opt}) {
c427973b
DM
4846 $conf->{$opt} = $conf->{pending}->{$opt};
4847 delete $conf->{pending}->{$opt};
4848 $changes = 1;
4849 }
4850 }
4851
4852 if ($changes) {
ffda963f
FG
4853 PVE::QemuConfig->write_config($vmid, $conf);
4854 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
c427973b
DM
4855 }
4856
b3c2bdd1 4857 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
c427973b 4858
98bc3aeb 4859 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 4860 foreach my $opt (sort keys %$pending_delete_hash) {
3a11fadb 4861 next if $selection && !$selection->{$opt};
d321c4a9 4862 my $force = $pending_delete_hash->{$opt}->{force};
3a11fadb 4863 eval {
51a6f637
AD
4864 if ($opt eq 'hotplug') {
4865 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4866 } elsif ($opt eq 'tablet') {
b3c2bdd1 4867 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4868 if ($defaults->{tablet}) {
d559309f
WB
4869 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4870 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4871 if $arch eq 'aarch64';
3a11fadb 4872 } else {
d559309f
WB
4873 vm_deviceunplug($vmid, $conf, 'tablet');
4874 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4875 }
4eb68604 4876 } elsif ($opt =~ m/^usb\d+/) {
f745762b
DC
4877 die "skip\n";
4878 # since we cannot reliably hot unplug usb devices
4879 # we are disabling it
4eb68604
DC
4880 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4881 vm_deviceunplug($vmid, $conf, $opt);
8edc9c08 4882 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4883 die "skip\n" if !$hotplug_features->{cpu};
8edc9c08 4884 qemu_cpu_hotplug($vmid, $conf, undef);
9c2f7069 4885 } elsif ($opt eq 'balloon') {
81d95ae1 4886 # enable balloon device is not hotpluggable
75b51053
DC
4887 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4888 # here we reset the ballooning value to memory
4889 my $balloon = $conf->{memory} || $defaults->{memory};
4890 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
81d95ae1
DM
4891 } elsif ($fast_plug_option->{$opt}) {
4892 # do nothing
3eec5767 4893 } elsif ($opt =~ m/^net(\d+)$/) {
b3c2bdd1 4894 die "skip\n" if !$hotplug_features->{network};
3eec5767 4895 vm_deviceunplug($vmid, $conf, $opt);
74479ee9 4896 } elsif (is_valid_drivename($opt)) {
b3c2bdd1 4897 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
19120f99 4898 vm_deviceunplug($vmid, $conf, $opt);
3dc38fbb 4899 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4d3f29ed
AD
4900 } elsif ($opt =~ m/^memory$/) {
4901 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4902 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
c8effec3
AD
4903 } elsif ($opt eq 'cpuunits') {
4904 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
58be00f1
AD
4905 } elsif ($opt eq 'cpulimit') {
4906 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
3d7389fe 4907 } else {
e56beeda 4908 die "skip\n";
3d7389fe 4909 }
3a11fadb
DM
4910 };
4911 if (my $err = $@) {
e56beeda
DM
4912 &$add_error($opt, $err) if $err ne "skip\n";
4913 } else {
3a11fadb
DM
4914 # save new config if hotplug was successful
4915 delete $conf->{$opt};
98bc3aeb 4916 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
ffda963f
FG
4917 PVE::QemuConfig->write_config($vmid, $conf);
4918 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
3d7389fe 4919 }
3d7389fe
DM
4920 }
4921
9ed7a77c
WB
4922 my $apply_pending_cloudinit;
4923 $apply_pending_cloudinit = sub {
4924 my ($key, $value) = @_;
4925 $apply_pending_cloudinit = sub {}; # once is enough
4926
4927 my @cloudinit_opts = keys %$confdesc_cloudinit;
4928 foreach my $opt (keys %{$conf->{pending}}) {
4929 next if !grep { $_ eq $opt } @cloudinit_opts;
4930 $conf->{$opt} = delete $conf->{pending}->{$opt};
4931 }
4932
4933 my $new_conf = { %$conf };
4934 $new_conf->{$key} = $value;
4935 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4936 };
4937
3d7389fe 4938 foreach my $opt (keys %{$conf->{pending}}) {
3a11fadb 4939 next if $selection && !$selection->{$opt};
3d7389fe 4940 my $value = $conf->{pending}->{$opt};
3a11fadb 4941 eval {
51a6f637
AD
4942 if ($opt eq 'hotplug') {
4943 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4944 } elsif ($opt eq 'tablet') {
b3c2bdd1 4945 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4946 if ($value == 1) {
d559309f
WB
4947 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4948 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4949 if $arch eq 'aarch64';
3a11fadb 4950 } elsif ($value == 0) {
d559309f
WB
4951 vm_deviceunplug($vmid, $conf, 'tablet');
4952 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4953 }
4eb68604 4954 } elsif ($opt =~ m/^usb\d+$/) {
f745762b
DC
4955 die "skip\n";
4956 # since we cannot reliably hot unplug usb devices
4957 # we are disabling it
4eb68604
DC
4958 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4959 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4960 die "skip\n" if !$d;
d559309f 4961 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
8edc9c08 4962 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4963 die "skip\n" if !$hotplug_features->{cpu};
3a11fadb
DM
4964 qemu_cpu_hotplug($vmid, $conf, $value);
4965 } elsif ($opt eq 'balloon') {
81d95ae1 4966 # enable/disable balloning device is not hotpluggable
8fe689e7 4967 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
a1b7d579 4968 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
81d95ae1
DM
4969 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4970
3a11fadb 4971 # allow manual ballooning if shares is set to zero
4cc1efa6 4972 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
9c2f7069
AD
4973 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4974 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4975 }
a1b7d579 4976 } elsif ($opt =~ m/^net(\d+)$/) {
3eec5767 4977 # some changes can be done without hotplug
a1b7d579 4978 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
d559309f 4979 $vmid, $opt, $value, $arch, $machine_type);
74479ee9 4980 } elsif (is_valid_drivename($opt)) {
a05cff86 4981 # some changes can be done without hotplug
9ed7a77c
WB
4982 my $drive = parse_drive($opt, $value);
4983 if (drive_is_cloudinit($drive)) {
4984 &$apply_pending_cloudinit($opt, $value);
4985 }
b3c2bdd1 4986 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
d559309f 4987 $vmid, $opt, $value, 1, $arch, $machine_type);
4d3f29ed
AD
4988 } elsif ($opt =~ m/^memory$/) { #dimms
4989 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4990 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
c8effec3
AD
4991 } elsif ($opt eq 'cpuunits') {
4992 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
58be00f1 4993 } elsif ($opt eq 'cpulimit') {
c6f773b8 4994 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
58be00f1 4995 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
3a11fadb 4996 } else {
e56beeda 4997 die "skip\n"; # skip non-hot-pluggable options
3d7389fe 4998 }
3a11fadb
DM
4999 };
5000 if (my $err = $@) {
e56beeda
DM
5001 &$add_error($opt, $err) if $err ne "skip\n";
5002 } else {
3a11fadb
DM
5003 # save new config if hotplug was successful
5004 $conf->{$opt} = $value;
5005 delete $conf->{pending}->{$opt};
ffda963f
FG
5006 PVE::QemuConfig->write_config($vmid, $conf);
5007 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
3d7389fe 5008 }
3d7389fe 5009 }
c427973b 5010}
055d554d 5011
3dc38fbb
WB
5012sub try_deallocate_drive {
5013 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
5014
5015 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
5016 my $volid = $drive->{file};
5017 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
5018 my $sid = PVE::Storage::parse_volume_id($volid);
5019 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
cee01bcb
WB
5020
5021 # check if the disk is really unused
cee01bcb 5022 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
77019edf 5023 if is_volume_in_use($storecfg, $conf, $key, $volid);
cee01bcb 5024 PVE::Storage::vdisk_free($storecfg, $volid);
3dc38fbb 5025 return 1;
40b977f3
WL
5026 } else {
5027 # If vm is not owner of this disk remove from config
5028 return 1;
3dc38fbb
WB
5029 }
5030 }
5031
5032 return undef;
5033}
5034
5035sub vmconfig_delete_or_detach_drive {
5036 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
5037
5038 my $drive = parse_drive($opt, $conf->{$opt});
5039
5040 my $rpcenv = PVE::RPCEnvironment::get();
5041 my $authuser = $rpcenv->get_user();
5042
5043 if ($force) {
5044 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
5045 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
5046 } else {
5047 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
5048 }
5049}
5050
98bc3aeb
OB
5051
5052
055d554d 5053sub vmconfig_apply_pending {
3a11fadb 5054 my ($vmid, $conf, $storecfg) = @_;
c427973b
DM
5055
5056 # cold plug
055d554d 5057
98bc3aeb 5058 my $pending_delete_hash = PVE::QemuConfig->parse_pending_delete($conf->{pending}->{delete});
d321c4a9 5059 foreach my $opt (sort keys %$pending_delete_hash) {
055d554d 5060 die "internal error" if $opt =~ m/^unused/;
fb4d1ba2 5061 my $force = $pending_delete_hash->{$opt}->{force};
ffda963f 5062 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
055d554d 5063 if (!defined($conf->{$opt})) {
98bc3aeb 5064 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
ffda963f 5065 PVE::QemuConfig->write_config($vmid, $conf);
74479ee9 5066 } elsif (is_valid_drivename($opt)) {
3dc38fbb 5067 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
98bc3aeb 5068 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
055d554d 5069 delete $conf->{$opt};
ffda963f 5070 PVE::QemuConfig->write_config($vmid, $conf);
055d554d 5071 } else {
98bc3aeb 5072 PVE::QemuConfig->remove_from_pending_delete($conf, $opt);
055d554d 5073 delete $conf->{$opt};
ffda963f 5074 PVE::QemuConfig->write_config($vmid, $conf);
055d554d
DM
5075 }
5076 }
5077
ffda963f 5078 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
055d554d
DM
5079
5080 foreach my $opt (keys %{$conf->{pending}}) { # add/change
ffda963f 5081 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
055d554d
DM
5082
5083 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
5084 # skip if nothing changed
74479ee9 5085 } elsif (is_valid_drivename($opt)) {
055d554d
DM
5086 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
5087 if defined($conf->{$opt});
5088 $conf->{$opt} = $conf->{pending}->{$opt};
5089 } else {
5090 $conf->{$opt} = $conf->{pending}->{$opt};
5091 }
5092
5093 delete $conf->{pending}->{$opt};
ffda963f 5094 PVE::QemuConfig->write_config($vmid, $conf);
055d554d
DM
5095 }
5096}
5097
3eec5767
DM
5098my $safe_num_ne = sub {
5099 my ($a, $b) = @_;
5100
5101 return 0 if !defined($a) && !defined($b);
5102 return 1 if !defined($a);
5103 return 1 if !defined($b);
5104
5105 return $a != $b;
5106};
5107
5108my $safe_string_ne = sub {
5109 my ($a, $b) = @_;
5110
5111 return 0 if !defined($a) && !defined($b);
5112 return 1 if !defined($a);
5113 return 1 if !defined($b);
5114
5115 return $a ne $b;
5116};
5117
5118sub vmconfig_update_net {
d559309f 5119 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
3eec5767
DM
5120
5121 my $newnet = parse_net($value);
5122
5123 if ($conf->{$opt}) {
5124 my $oldnet = parse_net($conf->{$opt});
5125
5126 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
5127 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
5128 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
5129 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
5130
5131 # for non online change, we try to hot-unplug
7196b757 5132 die "skip\n" if !$hotplug;
3eec5767
DM
5133 vm_deviceunplug($vmid, $conf, $opt);
5134 } else {
5135
5136 die "internal error" if $opt !~ m/net(\d+)/;
5137 my $iface = "tap${vmid}i$1";
a1b7d579 5138
25088687
DM
5139 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
5140 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
16d08ecf 5141 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
25088687 5142 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
3eec5767 5143 PVE::Network::tap_unplug($iface);
4f4fbeb0
WB
5144 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5145 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
5146 # Rate can be applied on its own but any change above needs to
5147 # include the rate in tap_plug since OVS resets everything.
5148 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
3eec5767 5149 }
38c590d9 5150
25088687
DM
5151 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
5152 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5153 }
5154
38c590d9 5155 return 1;
3eec5767
DM
5156 }
5157 }
a1b7d579 5158
7196b757 5159 if ($hotplug) {
d559309f 5160 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
38c590d9
DM
5161 } else {
5162 die "skip\n";
5163 }
3eec5767
DM
5164}
5165
a05cff86 5166sub vmconfig_update_disk {
d559309f 5167 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
a05cff86
DM
5168
5169 # fixme: do we need force?
5170
5171 my $drive = parse_drive($opt, $value);
5172
5173 if ($conf->{$opt}) {
5174
5175 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
5176
5177 my $media = $drive->{media} || 'disk';
5178 my $oldmedia = $old_drive->{media} || 'disk';
5179 die "unable to change media type\n" if $media ne $oldmedia;
5180
5181 if (!drive_is_cdrom($old_drive)) {
5182
a1b7d579 5183 if ($drive->{file} ne $old_drive->{file}) {
a05cff86 5184
7196b757 5185 die "skip\n" if !$hotplug;
a05cff86
DM
5186
5187 # unplug and register as unused
5188 vm_deviceunplug($vmid, $conf, $opt);
5189 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
a1b7d579 5190
a05cff86
DM
5191 } else {
5192 # update existing disk
5193
5194 # skip non hotpluggable value
6ecfbb44 5195 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
22de899a 5196 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
6e11f143 5197 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
a05cff86
DM
5198 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
5199 die "skip\n";
5200 }
5201
5202 # apply throttle
5203 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5204 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5205 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5206 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5207 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5208 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5209 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5210 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5211 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5212 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5213 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
9196a8ec
WB
5214 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5215 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5216 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5217 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5218 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5219 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5220 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
a1b7d579 5221
a05cff86
DM
5222 qemu_block_set_io_throttle($vmid,"drive-$opt",
5223 ($drive->{mbps} || 0)*1024*1024,
5224 ($drive->{mbps_rd} || 0)*1024*1024,
5225 ($drive->{mbps_wr} || 0)*1024*1024,
5226 $drive->{iops} || 0,
5227 $drive->{iops_rd} || 0,
5228 $drive->{iops_wr} || 0,
5229 ($drive->{mbps_max} || 0)*1024*1024,
5230 ($drive->{mbps_rd_max} || 0)*1024*1024,
5231 ($drive->{mbps_wr_max} || 0)*1024*1024,
5232 $drive->{iops_max} || 0,
5233 $drive->{iops_rd_max} || 0,
9196a8ec
WB
5234 $drive->{iops_wr_max} || 0,
5235 $drive->{bps_max_length} || 1,
5236 $drive->{bps_rd_max_length} || 1,
5237 $drive->{bps_wr_max_length} || 1,
5238 $drive->{iops_max_length} || 1,
5239 $drive->{iops_rd_max_length} || 1,
5240 $drive->{iops_wr_max_length} || 1);
a05cff86
DM
5241
5242 }
a1b7d579 5243
a05cff86
DM
5244 return 1;
5245 }
4de1bb25
DM
5246
5247 } else { # cdrom
a1b7d579 5248
4de1bb25
DM
5249 if ($drive->{file} eq 'none') {
5250 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
2d9ddec5
WB
5251 if (drive_is_cloudinit($old_drive)) {
5252 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5253 }
4de1bb25
DM
5254 } else {
5255 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5256 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5257 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5258 }
a1b7d579 5259
34758d66 5260 return 1;
a05cff86
DM
5261 }
5262 }
5263 }
5264
a1b7d579 5265 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4de1bb25 5266 # hotplug new disks
f7b4356f 5267 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
d559309f 5268 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
a05cff86
DM
5269}
5270
1e3baf05 5271sub vm_start {
ba9e1000 5272 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
2189246c 5273 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
1e3baf05 5274
ffda963f
FG
5275 PVE::QemuConfig->lock_config($vmid, sub {
5276 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
1e3baf05 5277
ffda963f 5278 die "you can't start a vm if it's a template\n" if PVE::QemuConfig->is_template($conf);
3dcb98d5 5279
7ceade4c
DC
5280 my $is_suspended = PVE::QemuConfig->has_lock($conf, 'suspended');
5281
5282 PVE::QemuConfig->check_lock($conf)
5283 if !($skiplock || $is_suspended);
1e3baf05 5284
7e8dcf2c 5285 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
1e3baf05 5286
64457ed4
DC
5287 # clean up leftover reboot request files
5288 eval { clear_reboot_request($vmid); };
5289 warn $@ if $@;
5290
055d554d 5291 if (!$statefile && scalar(keys %{$conf->{pending}})) {
3a11fadb 5292 vmconfig_apply_pending($vmid, $conf, $storecfg);
ffda963f 5293 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
055d554d
DM
5294 }
5295
0c9a7596
AD
5296 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5297
6c47d546
DM
5298 my $defaults = load_defaults();
5299
5300 # set environment variable useful inside network script
5301 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5302
2189246c
AD
5303 my $local_volumes = {};
5304
3b4cf0f0 5305 if ($targetstorage) {
2189246c
AD
5306 foreach_drive($conf, sub {
5307 my ($ds, $drive) = @_;
5308
5309 return if drive_is_cdrom($drive);
5310
5311 my $volid = $drive->{file};
5312
5313 return if !$volid;
5314
5315 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5316
5317 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5318 return if $scfg->{shared};
5319 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5320 });
5321
5322 my $format = undef;
5323
5324 foreach my $opt (sort keys %$local_volumes) {
5325
5326 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5327 my $drive = parse_drive($opt, $conf->{$opt});
5328
5329 #if remote storage is specified, use default format
5330 if ($targetstorage && $targetstorage ne "1") {
5331 $storeid = $targetstorage;
5332 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5333 $format = $defFormat;
5334 } else {
5335 #else we use same format than original
5336 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5337 $format = qemu_img_format($scfg, $volid);
5338 }
5339
5340 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5341 my $newdrive = $drive;
5342 $newdrive->{format} = $format;
5343 $newdrive->{file} = $newvolid;
5344 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5345 $local_volumes->{$opt} = $drivestr;
5346 #pass drive to conf for command line
5347 $conf->{$opt} = $drivestr;
5348 }
5349 }
5350
9e784b11
DC
5351 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1);
5352
7ceade4c
DC
5353 if ($is_suspended) {
5354 # enforce machine type on suspended vm to ensure HW compatibility
5355 $forcemachine = $conf->{runningmachine};
b0a9a385 5356 print "Resuming suspended VM\n";
7ceade4c
DC
5357 }
5358
67812f9c 5359 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
6c47d546 5360
5bc1e039 5361 my $migrate_uri;
1e3baf05
DM
5362 if ($statefile) {
5363 if ($statefile eq 'tcp') {
5bc1e039
SP
5364 my $localip = "localhost";
5365 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
af0eba7e 5366 my $nodename = PVE::INotify::nodename();
2de2d6f7 5367
b7a5a225
TL
5368 if (!defined($migration_type)) {
5369 if (defined($datacenterconf->{migration}->{type})) {
5370 $migration_type = $datacenterconf->{migration}->{type};
5371 } else {
5372 $migration_type = 'secure';
5373 }
5374 }
5375
2de2d6f7
TL
5376 if ($migration_type eq 'insecure') {
5377 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5378 if ($migrate_network_addr) {
5379 $localip = $migrate_network_addr;
5380 } else {
5bc1e039 5381 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
2de2d6f7
TL
5382 }
5383
5384 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5bc1e039 5385 }
2de2d6f7 5386
af0eba7e 5387 my $pfamily = PVE::Tools::get_host_address_family($nodename);
a447e92c 5388 my $migrate_port = PVE::Tools::next_migrate_port($pfamily);
407e0b8b 5389 $migrate_uri = "tcp:${localip}:${migrate_port}";
6c47d546
DM
5390 push @$cmd, '-incoming', $migrate_uri;
5391 push @$cmd, '-S';
1c9d54bf
TL
5392
5393 } elsif ($statefile eq 'unix') {
5394 # should be default for secure migrations as a ssh TCP forward
5395 # tunnel is not deterministic reliable ready and fails regurarly
5396 # to set up in time, so use UNIX socket forwards
54323eed
TL
5397 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5398 unlink $socket_addr;
5399
5400 $migrate_uri = "unix:$socket_addr";
1c9d54bf
TL
5401
5402 push @$cmd, '-incoming', $migrate_uri;
5403 push @$cmd, '-S';
5404
5c1d42b7 5405 } elsif (-e $statefile) {
6c47d546 5406 push @$cmd, '-loadstate', $statefile;
5c1d42b7
TL
5407 } else {
5408 my $statepath = PVE::Storage::path($storecfg, $statefile);
edcbf953 5409 push @$vollist, $statefile;
5c1d42b7 5410 push @$cmd, '-loadstate', $statepath;
1e3baf05 5411 }
91bd6c90
DM
5412 } elsif ($paused) {
5413 push @$cmd, '-S';
1e3baf05
DM
5414 }
5415
1e3baf05 5416 # host pci devices
040b06b7
DA
5417 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5418 my $d = parse_hostpci($conf->{"hostpci$i"});
5419 next if !$d;
b1f72af6
AD
5420 my $pcidevices = $d->{pciid};
5421 foreach my $pcidevice (@$pcidevices) {
2fd24788 5422 my $pciid = $pcidevice->{id};
000fc0a2 5423
b71351a7
DC
5424 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5425 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
b1f72af6 5426 die "no pci device info for device '$pciid'\n" if !$info;
6ab45bd7
DC
5427
5428 if ($d->{mdev}) {
5429 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5430 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5431 } else {
5432 die "can't unbind/bind pci group to vfio '$pciid'\n"
5433 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5434 die "can't reset pci device '$pciid'\n"
5435 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5436 }
b1f72af6 5437 }
040b06b7 5438 }
1e3baf05
DM
5439
5440 PVE::Storage::activate_volumes($storecfg, $vollist);
5441
4f8cfa19
WB
5442 eval {
5443 run_command(['/bin/systemctl', 'stop', "$vmid.scope"],
5444 outfunc => sub {}, errfunc => sub {});
5445 };
5446 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5447 # timeout should be more than enough here...
5448 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
2b401189 5449
8e59d952
WB
5450 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5451 : $defaults->{cpuunits};
5452
ccb2e2ea 5453 my $start_timeout = ($conf->{hugepages} || $is_suspended) ? 300 : 30;
f38de678 5454 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
7023f3ea
AD
5455
5456 my %properties = (
5457 Slice => 'qemu.slice',
5458 KillMode => 'none',
5459 CPUShares => $cpuunits
5460 );
5461
5462 if (my $cpulimit = $conf->{cpulimit}) {
5463 $properties{CPUQuota} = int($cpulimit * 100);
5464 }
5465 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5466
503308ed
WB
5467 my $run_qemu = sub {
5468 PVE::Tools::run_fork sub {
d04d6af1 5469 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
503308ed
WB
5470 run_command($cmd, %run_params);
5471 };
5472 };
5473
7023f3ea
AD
5474 if ($conf->{hugepages}) {
5475
5476 my $code = sub {
5477 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5478 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5479
5480 PVE::QemuServer::Memory::hugepages_mount();
5481 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5482
503308ed 5483 eval { $run_qemu->() };
7023f3ea
AD
5484 if (my $err = $@) {
5485 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5486 die $err;
5487 }
5488
5489 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5490 };
5491 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5492
5493 } else {
503308ed 5494 eval { $run_qemu->() };
7023f3ea 5495 }
77cde36b
DC
5496
5497 if (my $err = $@) {
5498 # deactivate volumes if start fails
5499 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5500 die "start failed: $err";
5501 }
1e3baf05 5502
5bc1e039 5503 print "migration listens on $migrate_uri\n" if $migrate_uri;
afdb31d5 5504
b37ecfe6 5505 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
95381ce0 5506 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
8c609afd 5507 warn $@ if $@;
62de2cbd
DM
5508 }
5509
2189246c
AD
5510 #start nbd server for storage migration
5511 if ($targetstorage) {
2189246c
AD
5512 my $nodename = PVE::INotify::nodename();
5513 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5514 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5515 my $pfamily = PVE::Tools::get_host_address_family($nodename);
a447e92c 5516 my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
2189246c 5517
a447e92c 5518 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet', data => { host => "${localip}", port => "${storage_migrate_port}" } } );
2189246c
AD
5519
5520 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5521
5522 foreach my $opt (sort keys %$local_volumes) {
5523 my $volid = $local_volumes->{$opt};
5524 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
a447e92c 5525 my $migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}:exportname=drive-$opt";
2189246c
AD
5526 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5527 }
5528 }
5529
1d794448 5530 if ($migratedfrom) {
a89fded1 5531 eval {
8e90138a 5532 set_migration_caps($vmid);
a89fded1 5533 };
1d794448 5534 warn $@ if $@;
a89fded1 5535
1d794448
DM
5536 if ($spice_port) {
5537 print "spice listens on port $spice_port\n";
5538 if ($spice_ticket) {
8e90138a
DM
5539 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice', password => $spice_ticket);
5540 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice', time => "+30");
95a4b4a9
AD
5541 }
5542 }
5543
1d794448 5544 } else {
51153f86
DC
5545 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5546 if !$statefile && $conf->{balloon};
25088687
DM
5547
5548 foreach my $opt (keys %$conf) {
5549 next if $opt !~ m/^net\d+$/;
5550 my $nicconf = parse_net($conf->{$opt});
5551 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5552 }
e18b0b99 5553 }
a1b7d579 5554
eb065317
AD
5555 vm_mon_cmd_nocheck($vmid, 'qom-set',
5556 path => "machine/peripheral/balloon0",
5557 property => "guest-stats-polling-interval",
5558 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5559
7ceade4c 5560 if ($is_suspended && (my $vmstate = $conf->{vmstate})) {
b0a9a385 5561 print "Resumed VM, removing state\n";
7ceade4c
DC
5562 delete $conf->@{qw(lock vmstate runningmachine)};
5563 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5564 PVE::Storage::vdisk_free($storecfg, $vmstate);
5565 PVE::QemuConfig->write_config($vmid, $conf);
5566 }
5567
9e784b11 5568 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start');
1e3baf05
DM
5569 });
5570}
5571
0eedc444
AD
5572sub vm_mon_cmd {
5573 my ($vmid, $execute, %params) = @_;
5574
26f11676
DM
5575 my $cmd = { execute => $execute, arguments => \%params };
5576 vm_qmp_command($vmid, $cmd);
0eedc444
AD
5577}
5578
5579sub vm_mon_cmd_nocheck {
5580 my ($vmid, $execute, %params) = @_;
5581
26f11676
DM
5582 my $cmd = { execute => $execute, arguments => \%params };
5583 vm_qmp_command($vmid, $cmd, 1);
0eedc444
AD
5584}
5585
c971c4f2 5586sub vm_qmp_command {
c5a07de5 5587 my ($vmid, $cmd, $nocheck) = @_;
97d62eb7 5588
c971c4f2 5589 my $res;
26f11676 5590
14db5366 5591 my $timeout;
1688362d
SR
5592 if ($cmd->{arguments}) {
5593 $timeout = delete $cmd->{arguments}->{timeout};
14db5366 5594 }
be190583 5595
c971c4f2
AD
5596 eval {
5597 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
7a6c2150
DM
5598 my $sname = qmp_socket($vmid);
5599 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
c5a07de5 5600 my $qmpclient = PVE::QMPClient->new();
dab36e1e 5601
14db5366 5602 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
dab36e1e
DM
5603 } else {
5604 die "unable to open monitor socket\n";
5605 }
c971c4f2 5606 };
26f11676 5607 if (my $err = $@) {
c971c4f2
AD
5608 syslog("err", "VM $vmid qmp command failed - $err");
5609 die $err;
5610 }
5611
5612 return $res;
5613}
5614
9df5cbcc
DM
5615sub vm_human_monitor_command {
5616 my ($vmid, $cmdline) = @_;
5617
f5eb281a 5618 my $cmd = {
9df5cbcc
DM
5619 execute => 'human-monitor-command',
5620 arguments => { 'command-line' => $cmdline},
5621 };
5622
5623 return vm_qmp_command($vmid, $cmd);
5624}
5625
1e3baf05 5626sub vm_commandline {
b14477e7 5627 my ($storecfg, $vmid, $snapname) = @_;
1e3baf05 5628
ffda963f 5629 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5630
b14477e7
RV
5631 if ($snapname) {
5632 my $snapshot = $conf->{snapshots}->{$snapname};
87d92707
TL
5633 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5634
5635 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
b14477e7 5636
b14477e7
RV
5637 $conf = $snapshot;
5638 }
5639
1e3baf05
DM
5640 my $defaults = load_defaults();
5641
6b64503e 5642 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
1e3baf05 5643
5930c1ff 5644 return PVE::Tools::cmd2string($cmd);
1e3baf05
DM
5645}
5646
5647sub vm_reset {
5648 my ($vmid, $skiplock) = @_;
5649
ffda963f 5650 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5651
ffda963f 5652 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5653
ffda963f 5654 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 5655
816e2c4a 5656 vm_mon_cmd($vmid, "system_reset");
ff1a2432
DM
5657 });
5658}
5659
5660sub get_vm_volumes {
5661 my ($conf) = @_;
1e3baf05 5662
ff1a2432 5663 my $vollist = [];
d5769dc2 5664 foreach_volid($conf, sub {
392f8b5d 5665 my ($volid, $attr) = @_;
ff1a2432 5666
d5769dc2 5667 return if $volid =~ m|^/|;
ff1a2432 5668
d5769dc2
DM
5669 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5670 return if !$sid;
ff1a2432
DM
5671
5672 push @$vollist, $volid;
1e3baf05 5673 });
ff1a2432
DM
5674
5675 return $vollist;
5676}
5677
5678sub vm_stop_cleanup {
70b04821 5679 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
ff1a2432 5680
745fed70 5681 eval {
ff1a2432 5682
254575e9
DM
5683 if (!$keepActive) {
5684 my $vollist = get_vm_volumes($conf);
5685 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5686 }
a1b7d579 5687
ab6a046f 5688 foreach my $ext (qw(mon qmp pid vnc qga)) {
961bfcb2
DM
5689 unlink "/var/run/qemu-server/${vmid}.$ext";
5690 }
a1b7d579 5691
6dbcb073
DC
5692 if ($conf->{ivshmem}) {
5693 my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
4c5a6a24
TL
5694 # just delete it for now, VMs which have this already open do not
5695 # are affected, but new VMs will get a separated one. If this
5696 # becomes an issue we either add some sort of ref-counting or just
5697 # add a "don't delete on stop" flag to the ivshmem format.
6dbcb073
DC
5698 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name} // $vmid);
5699 }
5700
6ab45bd7
DC
5701 foreach my $key (keys %$conf) {
5702 next if $key !~ m/^hostpci(\d+)$/;
5703 my $hostpciindex = $1;
5704 my $d = parse_hostpci($conf->{$key});
5705 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $hostpciindex);
5706
5707 foreach my $pci (@{$d->{pciid}}) {
2fd24788 5708 my $pciid = $pci->{id};
6ab45bd7
DC
5709 PVE::SysFSTools::pci_cleanup_mdev_device($pciid, $uuid);
5710 }
5711 }
5712
70b04821 5713 vmconfig_apply_pending($vmid, $conf, $storecfg) if $apply_pending_changes;
745fed70
DM
5714 };
5715 warn $@ if $@; # avoid errors - just warn
1e3baf05
DM
5716}
5717
575d19da
DC
5718# call only in locked context
5719sub _do_vm_stop {
5720 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive) = @_;
9269013a 5721
575d19da
DC
5722 my $pid = check_running($vmid, $nocheck);
5723 return if !$pid;
1e3baf05 5724
575d19da
DC
5725 my $conf;
5726 if (!$nocheck) {
5727 $conf = PVE::QemuConfig->load_config($vmid);
5728 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5729 if (!defined($timeout) && $shutdown && $conf->{startup}) {
5730 my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
5731 $timeout = $opts->{down} if $opts->{down};
e6c3b671 5732 }
575d19da
DC
5733 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-stop');
5734 }
19672434 5735
575d19da
DC
5736 eval {
5737 if ($shutdown) {
5738 if (defined($conf) && parse_guest_agent($conf)->{enabled}) {
5739 vm_qmp_command($vmid, {
0eb21691
SR
5740 execute => "guest-shutdown",
5741 arguments => { timeout => $timeout }
5742 }, $nocheck);
9269013a 5743 } else {
575d19da 5744 vm_qmp_command($vmid, { execute => "system_powerdown" }, $nocheck);
1e3baf05
DM
5745 }
5746 } else {
575d19da 5747 vm_qmp_command($vmid, { execute => "quit" }, $nocheck);
1e3baf05 5748 }
575d19da
DC
5749 };
5750 my $err = $@;
1e3baf05 5751
575d19da
DC
5752 if (!$err) {
5753 $timeout = 60 if !defined($timeout);
1e3baf05
DM
5754
5755 my $count = 0;
e6c3b671 5756 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
5757 $count++;
5758 sleep 1;
5759 }
5760
5761 if ($count >= $timeout) {
575d19da
DC
5762 if ($force) {
5763 warn "VM still running - terminating now with SIGTERM\n";
5764 kill 15, $pid;
5765 } else {
5766 die "VM quit/powerdown failed - got timeout\n";
5767 }
5768 } else {
5769 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5770 return;
1e3baf05 5771 }
575d19da
DC
5772 } else {
5773 if ($force) {
5774 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5775 kill 15, $pid;
5776 } else {
5777 die "VM quit/powerdown failed\n";
5778 }
5779 }
5780
5781 # wait again
5782 $timeout = 10;
5783
5784 my $count = 0;
5785 while (($count < $timeout) && check_running($vmid, $nocheck)) {
5786 $count++;
5787 sleep 1;
5788 }
5789
5790 if ($count >= $timeout) {
5791 warn "VM still running - terminating now with SIGKILL\n";
5792 kill 9, $pid;
5793 sleep 1;
5794 }
1e3baf05 5795
575d19da
DC
5796 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5797}
5798
5799# Note: use $nocheck to skip tests if VM configuration file exists.
5800# We need that when migration VMs to other nodes (files already moved)
5801# Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5802sub vm_stop {
5803 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5804
5805 $force = 1 if !defined($force) && !$shutdown;
5806
5807 if ($migratedfrom){
5808 my $pid = check_running($vmid, $nocheck, $migratedfrom);
5809 kill 15, $pid if $pid;
5810 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5811 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 0);
5812 return;
5813 }
5814
5815 PVE::QemuConfig->lock_config($vmid, sub {
5816 _do_vm_stop($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive);
ff1a2432 5817 });
1e3baf05
DM
5818}
5819
165411f0
DC
5820sub vm_reboot {
5821 my ($vmid, $timeout) = @_;
5822
5823 PVE::QemuConfig->lock_config($vmid, sub {
5824
5825 # only reboot if running, as qmeventd starts it again on a stop event
5826 return if !check_running($vmid);
5827
5828 create_reboot_request($vmid);
5829
5830 my $storecfg = PVE::Storage::config();
5831 _do_vm_stop($storecfg, $vmid, undef, undef, $timeout, 1);
5832
5833 });
5834}
5835
1e3baf05 5836sub vm_suspend {
48b4cdc2 5837 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
159719e5
DC
5838
5839 my $conf;
5840 my $path;
5841 my $storecfg;
5842 my $vmstate;
1e3baf05 5843
ffda963f 5844 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5845
159719e5 5846 $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5847
159719e5 5848 my $is_backing_up = PVE::QemuConfig->has_lock($conf, 'backup');
e79706d4 5849 PVE::QemuConfig->check_lock($conf)
159719e5
DC
5850 if !($skiplock || $is_backing_up);
5851
5852 die "cannot suspend to disk during backup\n"
5853 if $is_backing_up && $includestate;
bcb7c9cf 5854
159719e5
DC
5855 if ($includestate) {
5856 $conf->{lock} = 'suspending';
5857 my $date = strftime("%Y-%m-%d", localtime(time()));
5858 $storecfg = PVE::Storage::config();
48b4cdc2 5859 $vmstate = PVE::QemuConfig->__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
159719e5
DC
5860 $path = PVE::Storage::path($storecfg, $vmstate);
5861 PVE::QemuConfig->write_config($vmid, $conf);
5862 } else {
5863 vm_mon_cmd($vmid, "stop");
5864 }
1e3baf05 5865 });
159719e5
DC
5866
5867 if ($includestate) {
5868 # save vm state
5869 PVE::Storage::activate_volumes($storecfg, [$vmstate]);
5870
5871 eval {
5872 vm_mon_cmd($vmid, "savevm-start", statefile => $path);
5873 for(;;) {
5874 my $state = vm_mon_cmd_nocheck($vmid, "query-savevm");
5875 if (!$state->{status}) {
5876 die "savevm not active\n";
5877 } elsif ($state->{status} eq 'active') {
5878 sleep(1);
5879 next;
5880 } elsif ($state->{status} eq 'completed') {
b0a9a385 5881 print "State saved, quitting\n";
159719e5
DC
5882 last;
5883 } elsif ($state->{status} eq 'failed' && $state->{error}) {
5884 die "query-savevm failed with error '$state->{error}'\n"
5885 } else {
5886 die "query-savevm returned status '$state->{status}'\n";
5887 }
5888 }
5889 };
5890 my $err = $@;
5891
5892 PVE::QemuConfig->lock_config($vmid, sub {
5893 $conf = PVE::QemuConfig->load_config($vmid);
5894 if ($err) {
5895 # cleanup, but leave suspending lock, to indicate something went wrong
5896 eval {
5897 vm_mon_cmd($vmid, "savevm-end");
5898 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5899 PVE::Storage::vdisk_free($storecfg, $vmstate);
5900 delete $conf->@{qw(vmstate runningmachine)};
5901 PVE::QemuConfig->write_config($vmid, $conf);
5902 };
5903 warn $@ if $@;
5904 die $err;
5905 }
5906
5907 die "lock changed unexpectedly\n"
5908 if !PVE::QemuConfig->has_lock($conf, 'suspending');
5909
5910 vm_qmp_command($vmid, { execute => "quit" });
5911 $conf->{lock} = 'suspended';
5912 PVE::QemuConfig->write_config($vmid, $conf);
5913 });
5914 }
1e3baf05
DM
5915}
5916
5917sub vm_resume {
289e0b85 5918 my ($vmid, $skiplock, $nocheck) = @_;
1e3baf05 5919
ffda963f 5920 PVE::QemuConfig->lock_config($vmid, sub {
3e24733b
FG
5921 my $vm_mon_cmd = $nocheck ? \&vm_mon_cmd_nocheck : \&vm_mon_cmd;
5922 my $res = $vm_mon_cmd->($vmid, 'query-status');
c2786bed
DC
5923 my $resume_cmd = 'cont';
5924
5925 if ($res->{status} && $res->{status} eq 'suspended') {
5926 $resume_cmd = 'system_wakeup';
5927 }
5928
289e0b85 5929 if (!$nocheck) {
1e3baf05 5930
ffda963f 5931 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5932
e79706d4
FG
5933 PVE::QemuConfig->check_lock($conf)
5934 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
289e0b85 5935 }
3e24733b
FG
5936
5937 $vm_mon_cmd->($vmid, $resume_cmd);
1e3baf05
DM
5938 });
5939}
5940
5fdbe4f0
DM
5941sub vm_sendkey {
5942 my ($vmid, $skiplock, $key) = @_;
1e3baf05 5943
ffda963f 5944 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5945
ffda963f 5946 my $conf = PVE::QemuConfig->load_config($vmid);
f5eb281a 5947
7b7c6d1b 5948 # there is no qmp command, so we use the human monitor command
d30820d6
DC
5949 my $res = vm_human_monitor_command($vmid, "sendkey $key");
5950 die $res if $res ne '';
1e3baf05
DM
5951 });
5952}
5953
5954sub vm_destroy {
5955 my ($storecfg, $vmid, $skiplock) = @_;
5956
ffda963f 5957 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5958
ffda963f 5959 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5960
ff1a2432 5961 if (!check_running($vmid)) {
15cc8784 5962 destroy_vm($storecfg, $vmid, undef, $skiplock);
ff1a2432
DM
5963 } else {
5964 die "VM $vmid is running - destroy failed\n";
1e3baf05
DM
5965 }
5966 });
5967}
5968
3e16d5fc
DM
5969# vzdump restore implementaion
5970
ed221350 5971sub tar_archive_read_firstfile {
3e16d5fc 5972 my $archive = shift;
afdb31d5 5973
3e16d5fc
DM
5974 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
5975
5976 # try to detect archive type first
387ba257 5977 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
3e16d5fc 5978 die "unable to open file '$archive'\n";
387ba257 5979 my $firstfile = <$fh>;
3e16d5fc 5980 kill 15, $pid;
387ba257 5981 close $fh;
3e16d5fc
DM
5982
5983 die "ERROR: archive contaions no data\n" if !$firstfile;
5984 chomp $firstfile;
5985
5986 return $firstfile;
5987}
5988
ed221350
DM
5989sub tar_restore_cleanup {
5990 my ($storecfg, $statfile) = @_;
3e16d5fc
DM
5991
5992 print STDERR "starting cleanup\n";
5993
5994 if (my $fd = IO::File->new($statfile, "r")) {
5995 while (defined(my $line = <$fd>)) {
5996 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5997 my $volid = $2;
5998 eval {
5999 if ($volid =~ m|^/|) {
6000 unlink $volid || die 'unlink failed\n';
6001 } else {
ed221350 6002 PVE::Storage::vdisk_free($storecfg, $volid);
3e16d5fc 6003 }
afdb31d5 6004 print STDERR "temporary volume '$volid' sucessfuly removed\n";
3e16d5fc
DM
6005 };
6006 print STDERR "unable to cleanup '$volid' - $@" if $@;
6007 } else {
6008 print STDERR "unable to parse line in statfile - $line";
afdb31d5 6009 }
3e16d5fc
DM
6010 }
6011 $fd->close();
6012 }
6013}
6014
6015sub restore_archive {
a0d1b1a2 6016 my ($archive, $vmid, $user, $opts) = @_;
3e16d5fc 6017
91bd6c90
DM
6018 my $format = $opts->{format};
6019 my $comp;
6020
6021 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
6022 $format = 'tar' if !$format;
6023 $comp = 'gzip';
6024 } elsif ($archive =~ m/\.tar$/) {
6025 $format = 'tar' if !$format;
6026 } elsif ($archive =~ m/.tar.lzo$/) {
6027 $format = 'tar' if !$format;
6028 $comp = 'lzop';
6029 } elsif ($archive =~ m/\.vma$/) {
6030 $format = 'vma' if !$format;
6031 } elsif ($archive =~ m/\.vma\.gz$/) {
6032 $format = 'vma' if !$format;
6033 $comp = 'gzip';
6034 } elsif ($archive =~ m/\.vma\.lzo$/) {
6035 $format = 'vma' if !$format;
6036 $comp = 'lzop';
6037 } else {
6038 $format = 'vma' if !$format; # default
6039 }
6040
6041 # try to detect archive format
6042 if ($format eq 'tar') {
6043 return restore_tar_archive($archive, $vmid, $user, $opts);
6044 } else {
6045 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
6046 }
6047}
6048
6049sub restore_update_config_line {
6050 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
6051
6052 return if $line =~ m/^\#qmdump\#/;
6053 return if $line =~ m/^\#vzdump\#/;
6054 return if $line =~ m/^lock:/;
6055 return if $line =~ m/^unused\d+:/;
6056 return if $line =~ m/^parent:/;
6057
b5b99790 6058 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
91bd6c90
DM
6059 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6060 # try to convert old 1.X settings
6061 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6062 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
6063 my ($model, $macaddr) = split(/\=/, $devconfig);
b5b99790 6064 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
91bd6c90
DM
6065 my $net = {
6066 model => $model,
6067 bridge => "vmbr$ind",
6068 macaddr => $macaddr,
6069 };
6070 my $netstr = print_net($net);
6071
6072 print $outfd "net$cookie->{netcount}: $netstr\n";
6073 $cookie->{netcount}++;
6074 }
6075 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6076 my ($id, $netstr) = ($1, $2);
6077 my $net = parse_net($netstr);
b5b99790 6078 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
91bd6c90
DM
6079 $netstr = print_net($net);
6080 print $outfd "$id: $netstr\n";
6470743f 6081 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
91bd6c90 6082 my $virtdev = $1;
907ea891 6083 my $value = $3;
d9faf790
WB
6084 my $di = parse_drive($virtdev, $value);
6085 if (defined($di->{backup}) && !$di->{backup}) {
91bd6c90 6086 print $outfd "#$line";
c0f7406e 6087 } elsif ($map->{$virtdev}) {
8fd57431 6088 delete $di->{format}; # format can change on restore
91bd6c90 6089 $di->{file} = $map->{$virtdev};
ed221350 6090 $value = print_drive($vmid, $di);
91bd6c90
DM
6091 print $outfd "$virtdev: $value\n";
6092 } else {
6093 print $outfd $line;
6094 }
1a0c2f03 6095 } elsif (($line =~ m/^vmgenid: (.*)/)) {
babecffe 6096 my $vmgenid = $1;
6ee499ff 6097 if ($vmgenid ne '0') {
1a0c2f03 6098 # always generate a new vmgenid if there was a valid one setup
6ee499ff
DC
6099 $vmgenid = generate_uuid();
6100 }
1a0c2f03 6101 print $outfd "vmgenid: $vmgenid\n";
19a5dd55
WL
6102 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6103 my ($uuid, $uuid_str);
6104 UUID::generate($uuid);
6105 UUID::unparse($uuid, $uuid_str);
6106 my $smbios1 = parse_smbios1($2);
6107 $smbios1->{uuid} = $uuid_str;
6108 print $outfd $1.print_smbios1($smbios1)."\n";
91bd6c90
DM
6109 } else {
6110 print $outfd $line;
6111 }
6112}
6113
6114sub scan_volids {
6115 my ($cfg, $vmid) = @_;
6116
6117 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid);
6118
6119 my $volid_hash = {};
6120 foreach my $storeid (keys %$info) {
6121 foreach my $item (@{$info->{$storeid}}) {
6122 next if !($item->{volid} && $item->{size});
5996a936 6123 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
91bd6c90
DM
6124 $volid_hash->{$item->{volid}} = $item;
6125 }
6126 }
6127
6128 return $volid_hash;
6129}
6130
77019edf
WB
6131sub is_volume_in_use {
6132 my ($storecfg, $conf, $skip_drive, $volid) = @_;
a8e2f942 6133
77019edf 6134 my $path = PVE::Storage::path($storecfg, $volid);
a8e2f942
DM
6135
6136 my $scan_config = sub {
6137 my ($cref, $snapname) = @_;
6138
6139 foreach my $key (keys %$cref) {
6140 my $value = $cref->{$key};
74479ee9 6141 if (is_valid_drivename($key)) {
a8e2f942
DM
6142 next if $skip_drive && $key eq $skip_drive;
6143 my $drive = parse_drive($key, $value);
6144 next if !$drive || !$drive->{file} || drive_is_cdrom($drive);
77019edf 6145 return 1 if $volid eq $drive->{file};
a8e2f942 6146 if ($drive->{file} =~ m!^/!) {
77019edf 6147 return 1 if $drive->{file} eq $path;
a8e2f942
DM
6148 } else {
6149 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file}, 1);
6150 next if !$storeid;
6151 my $scfg = PVE::Storage::storage_config($storecfg, $storeid, 1);
6152 next if !$scfg;
77019edf 6153 return 1 if $path eq PVE::Storage::path($storecfg, $drive->{file}, $snapname);
a8e2f942
DM
6154 }
6155 }
6156 }
77019edf
WB
6157
6158 return 0;
a8e2f942
DM
6159 };
6160
77019edf 6161 return 1 if &$scan_config($conf);
a8e2f942
DM
6162
6163 undef $skip_drive;
6164
77019edf
WB
6165 foreach my $snapname (keys %{$conf->{snapshots}}) {
6166 return 1 if &$scan_config($conf->{snapshots}->{$snapname}, $snapname);
a8e2f942
DM
6167 }
6168
77019edf 6169 return 0;
a8e2f942
DM
6170}
6171
91bd6c90
DM
6172sub update_disksize {
6173 my ($vmid, $conf, $volid_hash) = @_;
be190583 6174
91bd6c90 6175 my $changes;
53b81297 6176 my $prefix = "VM $vmid:";
91bd6c90 6177
c449137a
DC
6178 # used and unused disks
6179 my $referenced = {};
91bd6c90 6180
5996a936
DM
6181 # Note: it is allowed to define multiple storages with same path (alias), so
6182 # we need to check both 'volid' and real 'path' (two different volid can point
6183 # to the same path).
6184
c449137a 6185 my $referencedpath = {};
be190583 6186
91bd6c90
DM
6187 # update size info
6188 foreach my $opt (keys %$conf) {
74479ee9 6189 if (is_valid_drivename($opt)) {
ed221350 6190 my $drive = parse_drive($opt, $conf->{$opt});
91bd6c90
DM
6191 my $volid = $drive->{file};
6192 next if !$volid;
6193
c449137a 6194 $referenced->{$volid} = 1;
be190583 6195 if ($volid_hash->{$volid} &&
5996a936 6196 (my $path = $volid_hash->{$volid}->{path})) {
c449137a 6197 $referencedpath->{$path} = 1;
5996a936 6198 }
91bd6c90 6199
ed221350 6200 next if drive_is_cdrom($drive);
91bd6c90
DM
6201 next if !$volid_hash->{$volid};
6202
6203 $drive->{size} = $volid_hash->{$volid}->{size};
7a907ce6
DM
6204 my $new = print_drive($vmid, $drive);
6205 if ($new ne $conf->{$opt}) {
6206 $changes = 1;
6207 $conf->{$opt} = $new;
53b81297 6208 print "$prefix update disk '$opt' information.\n";
7a907ce6 6209 }
91bd6c90
DM
6210 }
6211 }
6212
5996a936
DM
6213 # remove 'unusedX' entry if volume is used
6214 foreach my $opt (keys %$conf) {
6215 next if $opt !~ m/^unused\d+$/;
6216 my $volid = $conf->{$opt};
6217 my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
c449137a 6218 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
53b81297 6219 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5996a936
DM
6220 $changes = 1;
6221 delete $conf->{$opt};
6222 }
c449137a
DC
6223
6224 $referenced->{$volid} = 1;
6225 $referencedpath->{$path} = 1 if $path;
5996a936
DM
6226 }
6227
91bd6c90
DM
6228 foreach my $volid (sort keys %$volid_hash) {
6229 next if $volid =~ m/vm-$vmid-state-/;
c449137a 6230 next if $referenced->{$volid};
5996a936
DM
6231 my $path = $volid_hash->{$volid}->{path};
6232 next if !$path; # just to be sure
c449137a 6233 next if $referencedpath->{$path};
91bd6c90 6234 $changes = 1;
53b81297
TL
6235 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
6236 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
c449137a 6237 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
91bd6c90
DM
6238 }
6239
6240 return $changes;
6241}
6242
6243sub rescan {
9224dcee 6244 my ($vmid, $nolock, $dryrun) = @_;
91bd6c90 6245
20519efc 6246 my $cfg = PVE::Storage::config();
91bd6c90 6247
b9a1a3ab
TL
6248 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
6249 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
4771526a
AA
6250 foreach my $stor (keys %{$cfg->{ids}}) {
6251 delete($cfg->{ids}->{$stor}) if ! $cfg->{ids}->{$stor}->{content}->{images};
6252 }
6253
53b81297 6254 print "rescan volumes...\n";
91bd6c90
DM
6255 my $volid_hash = scan_volids($cfg, $vmid);
6256
6257 my $updatefn = sub {
6258 my ($vmid) = @_;
6259
ffda963f 6260 my $conf = PVE::QemuConfig->load_config($vmid);
be190583 6261
ffda963f 6262 PVE::QemuConfig->check_lock($conf);
91bd6c90 6263
03da3f0d
DM
6264 my $vm_volids = {};
6265 foreach my $volid (keys %$volid_hash) {
6266 my $info = $volid_hash->{$volid};
6267 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
6268 }
6269
6270 my $changes = update_disksize($vmid, $conf, $vm_volids);
91bd6c90 6271
9224dcee 6272 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
91bd6c90
DM
6273 };
6274
6275 if (defined($vmid)) {
6276 if ($nolock) {
6277 &$updatefn($vmid);
6278 } else {
ffda963f 6279 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
91bd6c90
DM
6280 }
6281 } else {
6282 my $vmlist = config_list();
6283 foreach my $vmid (keys %$vmlist) {
6284 if ($nolock) {
6285 &$updatefn($vmid);
6286 } else {
ffda963f 6287 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
be190583 6288 }
91bd6c90
DM
6289 }
6290 }
6291}
6292
6293sub restore_vma_archive {
6294 my ($archive, $vmid, $user, $opts, $comp) = @_;
6295
91bd6c90
DM
6296 my $readfrom = $archive;
6297
7c536e11
WB
6298 my $cfg = PVE::Storage::config();
6299 my $commands = [];
6300 my $bwlimit = $opts->{bwlimit};
6301
6302 my $dbg_cmdstring = '';
6303 my $add_pipe = sub {
6304 my ($cmd) = @_;
6305 push @$commands, $cmd;
6306 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6307 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
91bd6c90 6308 $readfrom = '-';
7c536e11
WB
6309 };
6310
6311 my $input = undef;
6312 if ($archive eq '-') {
6313 $input = '<&STDIN';
6314 } else {
6315 # If we use a backup from a PVE defined storage we also consider that
6316 # storage's rate limit:
6317 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
6318 if (defined($volid)) {
6319 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
6320 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
6321 if ($readlimit) {
6322 print STDERR "applying read rate limit: $readlimit\n";
9444c6e4 6323 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7c536e11
WB
6324 $add_pipe->($cstream);
6325 }
6326 }
6327 }
6328
6329 if ($comp) {
6330 my $cmd;
91bd6c90 6331 if ($comp eq 'gzip') {
7c536e11 6332 $cmd = ['zcat', $readfrom];
91bd6c90 6333 } elsif ($comp eq 'lzop') {
7c536e11 6334 $cmd = ['lzop', '-d', '-c', $readfrom];
91bd6c90
DM
6335 } else {
6336 die "unknown compression method '$comp'\n";
6337 }
7c536e11 6338 $add_pipe->($cmd);
91bd6c90
DM
6339 }
6340
6341 my $tmpdir = "/var/tmp/vzdumptmp$$";
6342 rmtree $tmpdir;
6343
6344 # disable interrupts (always do cleanups)
5b97ef24
TL
6345 local $SIG{INT} =
6346 local $SIG{TERM} =
6347 local $SIG{QUIT} =
6348 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
91bd6c90
DM
6349
6350 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6351 POSIX::mkfifo($mapfifo, 0600);
6352 my $fifofh;
6353
6354 my $openfifo = sub {
6355 open($fifofh, '>', $mapfifo) || die $!;
6356 };
6357
7c536e11 6358 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
91bd6c90
DM
6359
6360 my $oldtimeout;
6361 my $timeout = 5;
6362
6363 my $devinfo = {};
6364
6365 my $rpcenv = PVE::RPCEnvironment::get();
6366
ffda963f 6367 my $conffile = PVE::QemuConfig->config_file($vmid);
91bd6c90
DM
6368 my $tmpfn = "$conffile.$$.tmp";
6369
ed221350 6370 # Note: $oldconf is undef if VM does not exists
ffda963f
FG
6371 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6372 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
ed221350 6373
7c536e11
WB
6374 my %storage_limits;
6375
91bd6c90
DM
6376 my $print_devmap = sub {
6377 my $virtdev_hash = {};
6378
6379 my $cfgfn = "$tmpdir/qemu-server.conf";
6380
6381 # we can read the config - that is already extracted
6382 my $fh = IO::File->new($cfgfn, "r") ||
6383 "unable to read qemu-server.conf - $!\n";
6384
6738ab9c 6385 my $fwcfgfn = "$tmpdir/qemu-server.fw";
3457d090
WL
6386 if (-f $fwcfgfn) {
6387 my $pve_firewall_dir = '/etc/pve/firewall';
6388 mkdir $pve_firewall_dir; # make sure the dir exists
6389 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6390 }
6738ab9c 6391
91bd6c90
DM
6392 while (defined(my $line = <$fh>)) {
6393 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6394 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6395 die "archive does not contain data for drive '$virtdev'\n"
6396 if !$devinfo->{$devname};
6397 if (defined($opts->{storage})) {
6398 $storeid = $opts->{storage} || 'local';
6399 } elsif (!$storeid) {
6400 $storeid = 'local';
6401 }
6402 $format = 'raw' if !$format;
6403 $devinfo->{$devname}->{devname} = $devname;
6404 $devinfo->{$devname}->{virtdev} = $virtdev;
6405 $devinfo->{$devname}->{format} = $format;
6406 $devinfo->{$devname}->{storeid} = $storeid;
6407
be190583 6408 # check permission on storage
91bd6c90
DM
6409 my $pool = $opts->{pool}; # todo: do we need that?
6410 if ($user ne 'root@pam') {
6411 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6412 }
6413
7c536e11
WB
6414 $storage_limits{$storeid} = $bwlimit;
6415
91bd6c90 6416 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
c4ab3c55
ML
6417 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6418 my $virtdev = $1;
6419 my $drive = parse_drive($virtdev, $2);
6420 if (drive_is_cloudinit($drive)) {
6421 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
6422 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
6423 my $format = qemu_img_format($scfg, $volname); # has 'raw' fallback
6424
6425 my $d = {
6426 format => $format,
6427 storeid => $opts->{storage} // $storeid,
6428 size => PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE,
6429 file => $drive->{file}, # to make drive_is_cloudinit check possible
6430 name => "vm-$vmid-cloudinit",
87056e18 6431 is_cloudinit => 1,
c4ab3c55
ML
6432 };
6433 $virtdev_hash->{$virtdev} = $d;
6434 }
91bd6c90
DM
6435 }
6436 }
6437
7c536e11
WB
6438 foreach my $key (keys %storage_limits) {
6439 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$key], $bwlimit);
6440 next if !$limit;
6441 print STDERR "rate limit for storage $key: $limit KiB/s\n";
6442 $storage_limits{$key} = $limit * 1024;
6443 }
6444
91bd6c90 6445 foreach my $devname (keys %$devinfo) {
be190583
DM
6446 die "found no device mapping information for device '$devname'\n"
6447 if !$devinfo->{$devname}->{virtdev};
91bd6c90
DM
6448 }
6449
ed221350 6450 # create empty/temp config
be190583 6451 if ($oldconf) {
ed221350
DM
6452 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
6453 foreach_drive($oldconf, sub {
6454 my ($ds, $drive) = @_;
6455
a82348eb 6456 return if drive_is_cdrom($drive, 1);
ed221350
DM
6457
6458 my $volid = $drive->{file};
ed221350
DM
6459 return if !$volid || $volid =~ m|^/|;
6460
6461 my ($path, $owner) = PVE::Storage::path($cfg, $volid);
6462 return if !$path || !$owner || ($owner != $vmid);
6463
6464 # Note: only delete disk we want to restore
6465 # other volumes will become unused
6466 if ($virtdev_hash->{$ds}) {
6b72854b
FG
6467 eval { PVE::Storage::vdisk_free($cfg, $volid); };
6468 if (my $err = $@) {
6469 warn $err;
6470 }
ed221350
DM
6471 }
6472 });
381b8fae 6473
2b2923ae 6474 # delete vmstate files, after the restore we have no snapshots anymore
381b8fae
DC
6475 foreach my $snapname (keys %{$oldconf->{snapshots}}) {
6476 my $snap = $oldconf->{snapshots}->{$snapname};
6477 if ($snap->{vmstate}) {
6478 eval { PVE::Storage::vdisk_free($cfg, $snap->{vmstate}); };
6479 if (my $err = $@) {
6480 warn $err;
6481 }
6482 }
6483 }
ed221350
DM
6484 }
6485
6486 my $map = {};
91bd6c90
DM
6487 foreach my $virtdev (sort keys %$virtdev_hash) {
6488 my $d = $virtdev_hash->{$virtdev};
6489 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
7c536e11
WB
6490 my $storeid = $d->{storeid};
6491 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
6492
6493 my $map_opts = '';
6494 if (my $limit = $storage_limits{$storeid}) {
6495 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6496 }
8fd57431
DM
6497
6498 # test if requested format is supported
7c536e11 6499 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($cfg, $storeid);
8fd57431
DM
6500 my $supported = grep { $_ eq $d->{format} } @$validFormats;
6501 $d->{format} = $defFormat if !$supported;
6502
87056e18
TL
6503 my $name;
6504 if ($d->{is_cloudinit}) {
6505 $name = $d->{name};
6506 $name .= ".$d->{format}" if $d->{format} ne 'raw';
c4ab3c55 6507 }
2b2923ae
TL
6508
6509 my $volid = PVE::Storage::vdisk_alloc($cfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
91bd6c90
DM
6510 print STDERR "new volume ID is '$volid'\n";
6511 $d->{volid} = $volid;
91bd6c90 6512
2b2923ae 6513 PVE::Storage::activate_volumes($cfg, [$volid]);
5f96f4df 6514
91bd6c90 6515 my $write_zeros = 1;
88240a83 6516 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
91bd6c90
DM
6517 $write_zeros = 0;
6518 }
6519
87056e18
TL
6520 if (!$d->{is_cloudinit}) {
6521 my $path = PVE::Storage::path($cfg, $volid);
6522
c4ab3c55 6523 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
91bd6c90 6524
c4ab3c55
ML
6525 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6526 }
91bd6c90
DM
6527 $map->{$virtdev} = $volid;
6528 }
6529
6530 $fh->seek(0, 0) || die "seek failed - $!\n";
6531
6532 my $outfd = new IO::File ($tmpfn, "w") ||
6533 die "unable to write config for VM $vmid\n";
6534
6535 my $cookie = { netcount => 0 };
6536 while (defined(my $line = <$fh>)) {
be190583 6537 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
91bd6c90
DM
6538 }
6539
6540 $fh->close();
6541 $outfd->close();
6542 };
6543
6544 eval {
6545 # enable interrupts
6cb0144a
EK
6546 local $SIG{INT} =
6547 local $SIG{TERM} =
6548 local $SIG{QUIT} =
6549 local $SIG{HUP} =
6550 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
91bd6c90
DM
6551 local $SIG{ALRM} = sub { die "got timeout\n"; };
6552
6553 $oldtimeout = alarm($timeout);
6554
6555 my $parser = sub {
6556 my $line = shift;
6557
6558 print "$line\n";
6559
6560 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6561 my ($dev_id, $size, $devname) = ($1, $2, $3);
6562 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
6563 } elsif ($line =~ m/^CTIME: /) {
46f58b5f 6564 # we correctly received the vma config, so we can disable
3cf90d7a
DM
6565 # the timeout now for disk allocation (set to 10 minutes, so
6566 # that we always timeout if something goes wrong)
6567 alarm(600);
91bd6c90
DM
6568 &$print_devmap();
6569 print $fifofh "done\n";
6570 my $tmp = $oldtimeout || 0;
6571 $oldtimeout = undef;
6572 alarm($tmp);
6573 close($fifofh);
6574 }
6575 };
be190583 6576
7c536e11
WB
6577 print "restore vma archive: $dbg_cmdstring\n";
6578 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
91bd6c90
DM
6579 };
6580 my $err = $@;
6581
6582 alarm($oldtimeout) if $oldtimeout;
6583
5f96f4df
WL
6584 my $vollist = [];
6585 foreach my $devname (keys %$devinfo) {
6586 my $volid = $devinfo->{$devname}->{volid};
6587 push @$vollist, $volid if $volid;
6588 }
6589
5f96f4df
WL
6590 PVE::Storage::deactivate_volumes($cfg, $vollist);
6591
91bd6c90
DM
6592 unlink $mapfifo;
6593
6594 if ($err) {
6595 rmtree $tmpdir;
6596 unlink $tmpfn;
6597
91bd6c90
DM
6598 foreach my $devname (keys %$devinfo) {
6599 my $volid = $devinfo->{$devname}->{volid};
6600 next if !$volid;
6601 eval {
6602 if ($volid =~ m|^/|) {
6603 unlink $volid || die 'unlink failed\n';
6604 } else {
6605 PVE::Storage::vdisk_free($cfg, $volid);
6606 }
6607 print STDERR "temporary volume '$volid' sucessfuly removed\n";
6608 };
6609 print STDERR "unable to cleanup '$volid' - $@" if $@;
6610 }
6611 die $err;
6612 }
6613
6614 rmtree $tmpdir;
ed221350
DM
6615
6616 rename($tmpfn, $conffile) ||
91bd6c90
DM
6617 die "unable to commit configuration file '$conffile'\n";
6618
ed221350
DM
6619 PVE::Cluster::cfs_update(); # make sure we read new file
6620
91bd6c90
DM
6621 eval { rescan($vmid, 1); };
6622 warn $@ if $@;
6623}
6624
6625sub restore_tar_archive {
6626 my ($archive, $vmid, $user, $opts) = @_;
6627
9c502e26 6628 if ($archive ne '-') {
ed221350 6629 my $firstfile = tar_archive_read_firstfile($archive);
9c502e26
DM
6630 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6631 if $firstfile ne 'qemu-server.conf';
6632 }
3e16d5fc 6633
20519efc 6634 my $storecfg = PVE::Storage::config();
ebb55558 6635
ed221350 6636 # destroy existing data - keep empty config
ffda963f 6637 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
ebb55558 6638 destroy_vm($storecfg, $vmid, 1) if -f $vmcfgfn;
ed221350 6639
3e16d5fc
DM
6640 my $tocmd = "/usr/lib/qemu-server/qmextract";
6641
2415a446 6642 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
a0d1b1a2 6643 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
3e16d5fc
DM
6644 $tocmd .= ' --prealloc' if $opts->{prealloc};
6645 $tocmd .= ' --info' if $opts->{info};
6646
a0d1b1a2 6647 # tar option "xf" does not autodetect compression when read from STDIN,
9c502e26 6648 # so we pipe to zcat
2415a446
DM
6649 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
6650 PVE::Tools::shellquote("--to-command=$tocmd");
3e16d5fc
DM
6651
6652 my $tmpdir = "/var/tmp/vzdumptmp$$";
6653 mkpath $tmpdir;
6654
6655 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
6656 local $ENV{VZDUMP_VMID} = $vmid;
a0d1b1a2 6657 local $ENV{VZDUMP_USER} = $user;
3e16d5fc 6658
ffda963f 6659 my $conffile = PVE::QemuConfig->config_file($vmid);
3e16d5fc
DM
6660 my $tmpfn = "$conffile.$$.tmp";
6661
6662 # disable interrupts (always do cleanups)
6cb0144a
EK
6663 local $SIG{INT} =
6664 local $SIG{TERM} =
6665 local $SIG{QUIT} =
6666 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
3e16d5fc 6667
afdb31d5 6668 eval {
3e16d5fc 6669 # enable interrupts
6cb0144a
EK
6670 local $SIG{INT} =
6671 local $SIG{TERM} =
6672 local $SIG{QUIT} =
6673 local $SIG{HUP} =
6674 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
3e16d5fc 6675
9c502e26
DM
6676 if ($archive eq '-') {
6677 print "extracting archive from STDIN\n";
6678 run_command($cmd, input => "<&STDIN");
6679 } else {
6680 print "extracting archive '$archive'\n";
6681 run_command($cmd);
6682 }
3e16d5fc
DM
6683
6684 return if $opts->{info};
6685
6686 # read new mapping
6687 my $map = {};
6688 my $statfile = "$tmpdir/qmrestore.stat";
6689 if (my $fd = IO::File->new($statfile, "r")) {
6690 while (defined (my $line = <$fd>)) {
6691 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6692 $map->{$1} = $2 if $1;
6693 } else {
6694 print STDERR "unable to parse line in statfile - $line\n";
6695 }
6696 }
6697 $fd->close();
6698 }
6699
6700 my $confsrc = "$tmpdir/qemu-server.conf";
6701
6702 my $srcfd = new IO::File($confsrc, "r") ||
6703 die "unable to open file '$confsrc'\n";
6704
6705 my $outfd = new IO::File ($tmpfn, "w") ||
6706 die "unable to write config for VM $vmid\n";
6707
91bd6c90 6708 my $cookie = { netcount => 0 };
3e16d5fc 6709 while (defined (my $line = <$srcfd>)) {
be190583 6710 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
3e16d5fc
DM
6711 }
6712
6713 $srcfd->close();
6714 $outfd->close();
6715 };
6716 my $err = $@;
6717
afdb31d5 6718 if ($err) {
3e16d5fc
DM
6719
6720 unlink $tmpfn;
6721
ed221350 6722 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
afdb31d5 6723
3e16d5fc 6724 die $err;
afdb31d5 6725 }
3e16d5fc
DM
6726
6727 rmtree $tmpdir;
6728
6729 rename $tmpfn, $conffile ||
6730 die "unable to commit configuration file '$conffile'\n";
91bd6c90 6731
ed221350
DM
6732 PVE::Cluster::cfs_update(); # make sure we read new file
6733
91bd6c90
DM
6734 eval { rescan($vmid, 1); };
6735 warn $@ if $@;
3e16d5fc
DM
6736};
6737
65a5ce88 6738sub foreach_storage_used_by_vm {
18bfb361
DM
6739 my ($conf, $func) = @_;
6740
6741 my $sidhash = {};
6742
8ddbcf8b
FG
6743 foreach_drive($conf, sub {
6744 my ($ds, $drive) = @_;
6745 return if drive_is_cdrom($drive);
18bfb361
DM
6746
6747 my $volid = $drive->{file};
6748
6749 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
be190583 6750 $sidhash->{$sid} = $sid if $sid;
8ddbcf8b 6751 });
18bfb361
DM
6752
6753 foreach my $sid (sort keys %$sidhash) {
6754 &$func($sid);
6755 }
6756}
6757
e5eaa028
WL
6758sub do_snapshots_with_qemu {
6759 my ($storecfg, $volid) = @_;
6760
6761 my $storage_name = PVE::Storage::parse_volume_id($volid);
8aa2ed7c 6762 my $scfg = $storecfg->{ids}->{$storage_name};
e5eaa028 6763
8aa2ed7c 6764 if ($qemu_snap_storage->{$scfg->{type}} && !$scfg->{krbd}){
e5eaa028
WL
6765 return 1;
6766 }
6767
6768 if ($volid =~ m/\.(qcow2|qed)$/){
6769 return 1;
6770 }
6771
6772 return undef;
6773}
6774
4dcc780c 6775sub qga_check_running {
a4938c72 6776 my ($vmid, $nowarn) = @_;
4dcc780c
WL
6777
6778 eval { vm_mon_cmd($vmid, "guest-ping", timeout => 3); };
6779 if ($@) {
a4938c72 6780 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
4dcc780c
WL
6781 return 0;
6782 }
6783 return 1;
6784}
6785
04a69bb4
AD
6786sub template_create {
6787 my ($vmid, $conf, $disk) = @_;
6788
04a69bb4 6789 my $storecfg = PVE::Storage::config();
04a69bb4 6790
9cd07842
DM
6791 foreach_drive($conf, sub {
6792 my ($ds, $drive) = @_;
6793
6794 return if drive_is_cdrom($drive);
6795 return if $disk && $ds ne $disk;
6796
6797 my $volid = $drive->{file};
bbd56097 6798 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
9cd07842 6799
04a69bb4
AD
6800 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
6801 $drive->{file} = $voliddst;
152fe752 6802 $conf->{$ds} = print_drive($vmid, $drive);
ffda963f 6803 PVE::QemuConfig->write_config($vmid, $conf);
04a69bb4 6804 });
04a69bb4
AD
6805}
6806
92bdc3f0
DC
6807sub convert_iscsi_path {
6808 my ($path) = @_;
6809
6810 if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
6811 my $portal = $1;
6812 my $target = $2;
6813 my $lun = $3;
6814
6815 my $initiator_name = get_initiator_name();
6816
6817 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6818 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6819 }
6820
6821 die "cannot convert iscsi path '$path', unkown format\n";
6822}
6823
5133de42 6824sub qemu_img_convert {
988e2714 6825 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5133de42
AD
6826
6827 my $storecfg = PVE::Storage::config();
6828 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
6829 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
6830
af1f1ec0 6831 die "destination '$dst_volid' is not a valid volid form qemu-img convert\n" if !$dst_storeid;
6bb91c17 6832
af1f1ec0
DC
6833 my $cachemode;
6834 my $src_path;
6835 my $src_is_iscsi = 0;
6836 my $src_format = 'raw';
6bb91c17 6837
af1f1ec0
DC
6838 if ($src_storeid) {
6839 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
5133de42 6840 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
af1f1ec0
DC
6841 $src_format = qemu_img_format($src_scfg, $src_volname);
6842 $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
6843 $src_is_iscsi = ($src_path =~ m|^iscsi://|);
6844 $cachemode = 'none' if $src_scfg->{type} eq 'zfspool';
6845 } elsif (-f $src_volid) {
6846 $src_path = $src_volid;
6847 if ($src_path =~ m/\.($QEMU_FORMAT_RE)$/) {
6848 $src_format = $1;
6849 }
6850 }
5133de42 6851
af1f1ec0 6852 die "source '$src_volid' is not a valid volid nor path for qemu-img convert\n" if !$src_path;
5133de42 6853
af1f1ec0
DC
6854 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
6855 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
6856 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
6857 my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
5133de42 6858
af1f1ec0
DC
6859 my $cmd = [];
6860 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6861 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6862 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
6863 push @$cmd, '-T', $cachemode if defined($cachemode);
6864
6865 if ($src_is_iscsi) {
6866 push @$cmd, '--image-opts';
6867 $src_path = convert_iscsi_path($src_path);
6868 } else {
6869 push @$cmd, '-f', $src_format;
6870 }
92bdc3f0 6871
af1f1ec0
DC
6872 if ($dst_is_iscsi) {
6873 push @$cmd, '--target-image-opts';
6874 $dst_path = convert_iscsi_path($dst_path);
6875 } else {
6876 push @$cmd, '-O', $dst_format;
6877 }
92bdc3f0 6878
af1f1ec0 6879 push @$cmd, $src_path;
92bdc3f0 6880
af1f1ec0
DC
6881 if (!$dst_is_iscsi && $is_zero_initialized) {
6882 push @$cmd, "zeroinit:$dst_path";
6883 } else {
6884 push @$cmd, $dst_path;
6885 }
92bdc3f0 6886
af1f1ec0
DC
6887 my $parser = sub {
6888 my $line = shift;
6889 if($line =~ m/\((\S+)\/100\%\)/){
6890 my $percent = $1;
6891 my $transferred = int($size * $percent / 100);
6892 my $remaining = $size - $transferred;
92bdc3f0 6893
af1f1ec0 6894 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
988e2714 6895 }
5133de42 6896
af1f1ec0 6897 };
5133de42 6898
af1f1ec0
DC
6899 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
6900 my $err = $@;
6901 die "copy failed: $err" if $err;
5133de42
AD
6902}
6903
6904sub qemu_img_format {
6905 my ($scfg, $volname) = @_;
6906
9c52f5ed 6907 if ($scfg->{path} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
5133de42 6908 return $1;
be190583 6909 } else {
5133de42 6910 return "raw";
5133de42
AD
6911 }
6912}
6913
cfad42af 6914sub qemu_drive_mirror {
9fa05d31 6915 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
cfad42af 6916
5a345967
AD
6917 $jobs = {} if !$jobs;
6918
6919 my $qemu_target;
6920 my $format;
35e4ab04 6921 $jobs->{"drive-$drive"} = {};
152fe752 6922
1e5143de 6923 if ($dst_volid =~ /^nbd:/) {
87955688 6924 $qemu_target = $dst_volid;
5a345967 6925 $format = "nbd";
5a345967 6926 } else {
5a345967
AD
6927 my $storecfg = PVE::Storage::config();
6928 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
6929
6930 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
cfad42af 6931
5a345967 6932 $format = qemu_img_format($dst_scfg, $dst_volname);
21ccdb50 6933
5a345967 6934 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
21ccdb50 6935
5a345967
AD
6936 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
6937 }
988e2714
WB
6938
6939 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
88383920
DM
6940 $opts->{format} = $format if $format;
6941
9fa05d31 6942 if (defined($bwlimit)) {
f6409f61
TL
6943 $opts->{speed} = $bwlimit * 1024;
6944 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
9fa05d31
SI
6945 } else {
6946 print "drive mirror is starting for drive-$drive\n";
6947 }
21ccdb50 6948
6dde5ea2
TL
6949 # if a job already runs for this device we get an error, catch it for cleanup
6950 eval { vm_mon_cmd($vmid, "drive-mirror", %$opts); };
5a345967
AD
6951 if (my $err = $@) {
6952 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6dde5ea2
TL
6953 warn "$@\n" if $@;
6954 die "mirroring error: $err\n";
5a345967
AD
6955 }
6956
5619e74a 6957 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
5a345967
AD
6958}
6959
6960sub qemu_drive_mirror_monitor {
5619e74a 6961 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
2e953867 6962
08ac653f 6963 eval {
5a345967
AD
6964 my $err_complete = 0;
6965
08ac653f 6966 while (1) {
5a345967
AD
6967 die "storage migration timed out\n" if $err_complete > 300;
6968
08ac653f 6969 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
08ac653f 6970
5a345967
AD
6971 my $running_mirror_jobs = {};
6972 foreach my $stat (@$stats) {
6973 next if $stat->{type} ne 'mirror';
6974 $running_mirror_jobs->{$stat->{device}} = $stat;
6975 }
08ac653f 6976
5a345967 6977 my $readycounter = 0;
67fb9de6 6978
5a345967
AD
6979 foreach my $job (keys %$jobs) {
6980
6981 if(defined($jobs->{$job}->{complete}) && !defined($running_mirror_jobs->{$job})) {
6982 print "$job : finished\n";
6983 delete $jobs->{$job};
6984 next;
6985 }
6986
bd2d5fe6 6987 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
f34ebd52 6988
5a345967
AD
6989 my $busy = $running_mirror_jobs->{$job}->{busy};
6990 my $ready = $running_mirror_jobs->{$job}->{ready};
6991 if (my $total = $running_mirror_jobs->{$job}->{len}) {
6992 my $transferred = $running_mirror_jobs->{$job}->{offset} || 0;
6993 my $remaining = $total - $transferred;
6994 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
08ac653f 6995
5a345967
AD
6996 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6997 }
f34ebd52 6998
d1782eba 6999 $readycounter++ if $running_mirror_jobs->{$job}->{ready};
5a345967 7000 }
b467f79a 7001
5a345967
AD
7002 last if scalar(keys %$jobs) == 0;
7003
7004 if ($readycounter == scalar(keys %$jobs)) {
7005 print "all mirroring jobs are ready \n";
7006 last if $skipcomplete; #do the complete later
7007
7008 if ($vmiddst && $vmiddst != $vmid) {
1a988fd2
DC
7009 my $agent_running = $qga && qga_check_running($vmid);
7010 if ($agent_running) {
5619e74a
AD
7011 print "freeze filesystem\n";
7012 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-freeze"); };
7013 } else {
7014 print "suspend vm\n";
7015 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
7016 }
7017
5a345967
AD
7018 # if we clone a disk for a new target vm, we don't switch the disk
7019 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
5619e74a 7020
1a988fd2 7021 if ($agent_running) {
5619e74a
AD
7022 print "unfreeze filesystem\n";
7023 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-thaw"); };
7024 } else {
7025 print "resume vm\n";
7026 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
7027 }
7028
2e953867 7029 last;
5a345967
AD
7030 } else {
7031
7032 foreach my $job (keys %$jobs) {
7033 # try to switch the disk if source and destination are on the same guest
bd2d5fe6 7034 print "$job: Completing block job...\n";
5a345967
AD
7035
7036 eval { vm_mon_cmd($vmid, "block-job-complete", device => $job) };
7037 if ($@ =~ m/cannot be completed/) {
bd2d5fe6 7038 print "$job: Block job cannot be completed, try again.\n";
5a345967
AD
7039 $err_complete++;
7040 }else {
bd2d5fe6 7041 print "$job: Completed successfully.\n";
5a345967
AD
7042 $jobs->{$job}->{complete} = 1;
7043 }
7044 }
2e953867 7045 }
08ac653f 7046 }
08ac653f 7047 sleep 1;
cfad42af 7048 }
08ac653f 7049 };
88383920 7050 my $err = $@;
08ac653f 7051
88383920 7052 if ($err) {
5a345967 7053 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
88383920
DM
7054 die "mirroring error: $err";
7055 }
7056
5a345967
AD
7057}
7058
7059sub qemu_blockjobs_cancel {
7060 my ($vmid, $jobs) = @_;
7061
7062 foreach my $job (keys %$jobs) {
bd2d5fe6 7063 print "$job: Cancelling block job\n";
5a345967
AD
7064 eval { vm_mon_cmd($vmid, "block-job-cancel", device => $job); };
7065 $jobs->{$job}->{cancel} = 1;
7066 }
7067
7068 while (1) {
7069 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
7070
7071 my $running_jobs = {};
7072 foreach my $stat (@$stats) {
7073 $running_jobs->{$stat->{device}} = $stat;
7074 }
7075
7076 foreach my $job (keys %$jobs) {
7077
bd2d5fe6
WB
7078 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
7079 print "$job: Done.\n";
5a345967
AD
7080 delete $jobs->{$job};
7081 }
7082 }
7083
7084 last if scalar(keys %$jobs) == 0;
7085
7086 sleep 1;
cfad42af
AD
7087 }
7088}
7089
152fe752 7090sub clone_disk {
be190583 7091 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
7e303ef3 7092 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
152fe752
DM
7093
7094 my $newvolid;
7095
7096 if (!$full) {
7097 print "create linked clone of drive $drivename ($drive->{file})\n";
258e646c 7098 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
152fe752
DM
7099 push @$newvollist, $newvolid;
7100 } else {
5a345967 7101
152fe752
DM
7102 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
7103 $storeid = $storage if $storage;
7104
44549149 7105 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
152fe752
DM
7106 my ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 3);
7107
7108 print "create full clone of drive $drivename ($drive->{file})\n";
931432bd 7109 my $name = undef;
931432bd 7110 $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
152fe752
DM
7111 push @$newvollist, $newvolid;
7112
3999f370 7113 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
1dbd6d30 7114
988e2714 7115 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
152fe752 7116 if (!$running || $snapname) {
d189e590 7117 # TODO: handle bwlimits
988e2714 7118 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
152fe752 7119 } else {
2e541679
AD
7120
7121 my $kvmver = get_running_qemu_version ($vmid);
7122 if (!qemu_machine_feature_enabled (undef, $kvmver, 2, 7)) {
961af8a3
WB
7123 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7124 if $drive->{iothread};
2e541679 7125 }
2af848a2 7126
7e303ef3 7127 qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga, $bwlimit);
be190583 7128 }
152fe752
DM
7129 }
7130
7131 my ($size) = PVE::Storage::volume_size_info($storecfg, $newvolid, 3);
7132
7133 my $disk = $drive;
7134 $disk->{format} = undef;
7135 $disk->{file} = $newvolid;
7136 $disk->{size} = $size;
7137
7138 return $disk;
7139}
7140
ff556cf2
DM
7141# this only works if VM is running
7142sub get_current_qemu_machine {
7143 my ($vmid) = @_;
7144
7145 my $cmd = { execute => 'query-machines', arguments => {} };
8e90138a 7146 my $res = vm_qmp_command($vmid, $cmd);
ff556cf2
DM
7147
7148 my ($current, $default);
7149 foreach my $e (@$res) {
7150 $default = $e->{name} if $e->{'is-default'};
7151 $current = $e->{name} if $e->{'is-current'};
7152 }
7153
7154 # fallback to the default machine if current is not supported by qemu
7155 return $current || $default || 'pc';
7156}
7157
98cfd8b6
AD
7158sub get_running_qemu_version {
7159 my ($vmid) = @_;
7160 my $cmd = { execute => 'query-version', arguments => {} };
7161 my $res = vm_qmp_command($vmid, $cmd);
7162 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7163}
7164
23f73120
AD
7165sub qemu_machine_feature_enabled {
7166 my ($machine, $kvmver, $version_major, $version_minor) = @_;
7167
7168 my $current_major;
7169 my $current_minor;
7170
d731ecbe 7171 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
23f73120
AD
7172
7173 $current_major = $3;
7174 $current_minor = $4;
7175
7176 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
7177
7178 $current_major = $1;
7179 $current_minor = $2;
7180 }
7181
19e9b308
TL
7182 return 1 if version_cmp($current_major, $version_major, $current_minor, $version_minor) >= 0;
7183}
7184
7185# gets in pairs the versions you want to compares, i.e.:
7186# ($a-major, $b-major, $a-minor, $b-minor, $a-extra, $b-extra, ...)
7187# returns 0 if same, -1 if $a is older than $b, +1 if $a is newer than $b
7188sub version_cmp {
7189 my @versions = @_;
7190
7191 my $size = scalar(@versions);
7192
7193 return 0 if $size == 0;
7194 die "cannot compare odd count of versions" if $size & 1;
7195
7196 for (my $i = 0; $i < $size; $i += 2) {
7197 my ($a, $b) = splice(@versions, 0, 2);
7198 $a //= 0;
7199 $b //= 0;
7200
7201 return 1 if $a > $b;
7202 return -1 if $a < $b;
7203 }
7204 return 0;
23f73120
AD
7205}
7206
48343b3f
TL
7207sub runs_at_least_qemu_version {
7208 my ($vmid, $major, $minor, $extra) = @_;
7209
317c55c2 7210 my $v = eval { PVE::QemuServer::vm_qmp_command($vmid, { execute => 'query-version' }) } // {};
48343b3f
TL
7211 $v = $v->{qemu};
7212
7213 return version_cmp($v->{major}, $major, $v->{minor}, $minor, $v->{micro}, $extra) >= 0;
7214}
7215
42dbd2ee 7216sub qemu_machine_pxe {
8071149b 7217 my ($vmid, $conf) = @_;
42dbd2ee 7218
8071149b 7219 my $machine = PVE::QemuServer::get_current_qemu_machine($vmid);
42dbd2ee 7220
3807f3e4
DC
7221 if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
7222 $machine .= '.pxe';
42dbd2ee
AD
7223 }
7224
d1363934 7225 return $machine;
42dbd2ee
AD
7226}
7227
249c4a6c
AD
7228sub qemu_use_old_bios_files {
7229 my ($machine_type) = @_;
7230
7231 return if !$machine_type;
7232
7233 my $use_old_bios_files = undef;
7234
7235 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7236 $machine_type = $1;
7237 $use_old_bios_files = 1;
7238 } else {
74cc511f 7239 my $kvmver = kvm_user_version();
249c4a6c
AD
7240 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7241 # load new efi bios files on migration. So this hack is required to allow
7242 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7243 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
74cc511f 7244 $use_old_bios_files = !qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 4);
249c4a6c
AD
7245 }
7246
7247 return ($use_old_bios_files, $machine_type);
7248}
7249
96ed3574
WB
7250sub create_efidisk($$$$$) {
7251 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
3e1f1122 7252
96ed3574
WB
7253 my (undef, $ovmf_vars) = get_ovmf_files($arch);
7254 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
3e1f1122 7255
af1f1ec0
DC
7256 my $vars_size_b = -s $ovmf_vars;
7257 my $vars_size = PVE::Tools::convert_size($vars_size_b, 'b' => 'kb');
3e1f1122
TL
7258 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7259 PVE::Storage::activate_volumes($storecfg, [$volid]);
7260
af1f1ec0 7261 qemu_img_convert($ovmf_vars, $volid, $vars_size_b, undef, 0);
3e1f1122
TL
7262
7263 return ($volid, $vars_size);
7264}
7265
22de899a
AD
7266sub vm_iothreads_list {
7267 my ($vmid) = @_;
7268
7269 my $res = vm_mon_cmd($vmid, 'query-iothreads');
7270
7271 my $iothreads = {};
7272 foreach my $iothread (@$res) {
7273 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
7274 }
7275
7276 return $iothreads;
7277}
7278
ee034f5c
AD
7279sub scsihw_infos {
7280 my ($conf, $drive) = @_;
7281
7282 my $maxdev = 0;
7283
7fe1b688 7284 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
ee034f5c 7285 $maxdev = 7;
a1511b3c 7286 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
ee034f5c
AD
7287 $maxdev = 1;
7288 } else {
7289 $maxdev = 256;
7290 }
7291
7292 my $controller = int($drive->{index} / $maxdev);
a1511b3c 7293 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') ? "virtioscsi" : "scsihw";
ee034f5c
AD
7294
7295 return ($maxdev, $controller, $controller_prefix);
7296}
a1511b3c 7297
075e8249 7298sub add_hyperv_enlightenments {
2894c247 7299 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
4317f69f 7300
4317f69f
AD
7301 return if $winversion < 6;
7302 return if $bios && $bios eq 'ovmf' && $winversion < 8;
7303
2894c247
DC
7304 if ($gpu_passthrough || defined($hv_vendor_id)) {
7305 $hv_vendor_id //= 'proxmox';
7306 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
7307 }
5aba3953 7308
4317f69f
AD
7309 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
7310 push @$cpuFlags , 'hv_spinlocks=0x1fff';
7311 push @$cpuFlags , 'hv_vapic';
7312 push @$cpuFlags , 'hv_time';
7313 } else {
7314 push @$cpuFlags , 'hv_spinlocks=0xffff';
7315 }
7316
7317 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 6)) {
7318 push @$cpuFlags , 'hv_reset';
7319 push @$cpuFlags , 'hv_vpindex';
7320 push @$cpuFlags , 'hv_runtime';
7321 }
7322
7323 if ($winversion >= 7) {
7324 push @$cpuFlags , 'hv_relaxed';
ebb346d6 7325
df648a6a 7326 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 12)) {
ebb346d6
AD
7327 push @$cpuFlags , 'hv_synic';
7328 push @$cpuFlags , 'hv_stimer';
7329 }
392dfbf5 7330
392dfbf5
SR
7331 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 3, 1)) {
7332 push @$cpuFlags , 'hv_ipi';
392dfbf5 7333 }
4317f69f
AD
7334 }
7335}
7336
7337sub windows_version {
7338 my ($ostype) = @_;
7339
7340 return 0 if !$ostype;
7341
7342 my $winversion = 0;
7343
7344 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7345 $winversion = 5;
7346 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7347 $winversion = 6;
7348 } elsif ($ostype =~ m/^win(\d+)$/) {
7349 $winversion = $1;
7350 }
7351
7352 return $winversion;
7353}
7354
44549149
EK
7355sub resolve_dst_disk_format {
7356 my ($storecfg, $storeid, $src_volname, $format) = @_;
7357 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
7358
7359 if (!$format) {
7360 # if no target format is specified, use the source disk format as hint
7361 if ($src_volname) {
7362 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7363 $format = qemu_img_format($scfg, $src_volname);
7364 } else {
7365 return $defFormat;
7366 }
7367 }
7368
7369 # test if requested format is supported - else use default
7370 my $supported = grep { $_ eq $format } @$validFormats;
7371 $format = $defFormat if !$supported;
7372 return $format;
7373}
7374
ae2fcb3b
EK
7375sub resolve_first_disk {
7376 my $conf = shift;
7377 my @disks = PVE::QemuServer::valid_drive_names();
7378 my $firstdisk;
7379 foreach my $ds (reverse @disks) {
7380 next if !$conf->{$ds};
7381 my $disk = PVE::QemuServer::parse_drive($ds, $conf->{$ds});
7382 next if PVE::QemuServer::drive_is_cdrom($disk);
7383 $firstdisk = $ds;
7384 }
7385 return $firstdisk;
7386}
7387
6ee499ff 7388sub generate_uuid {
ae2fcb3b
EK
7389 my ($uuid, $uuid_str);
7390 UUID::generate($uuid);
7391 UUID::unparse($uuid, $uuid_str);
6ee499ff
DC
7392 return $uuid_str;
7393}
7394
7395sub generate_smbios1_uuid {
7396 return "uuid=".generate_uuid();
ae2fcb3b
EK
7397}
7398
9c152e87
TL
7399sub nbd_stop {
7400 my ($vmid) = @_;
7401
7402 vm_mon_cmd($vmid, 'nbd-server-stop');
7403}
7404
dae98db9
DC
7405sub create_reboot_request {
7406 my ($vmid) = @_;
7407 open(my $fh, '>', "/run/qemu-server/$vmid.reboot")
7408 or die "failed to create reboot trigger file: $!\n";
7409 close($fh);
7410}
7411
7412sub clear_reboot_request {
7413 my ($vmid) = @_;
7414 my $path = "/run/qemu-server/$vmid.reboot";
7415 my $res = 0;
7416
7417 $res = unlink($path);
7418 die "could not remove reboot request for $vmid: $!"
7419 if !$res && $! != POSIX::ENOENT;
7420
7421 return $res;
7422}
7423
65e866e5
DM
7424# bash completion helper
7425
7426sub complete_backup_archives {
7427 my ($cmdname, $pname, $cvalue) = @_;
7428
7429 my $cfg = PVE::Storage::config();
7430
7431 my $storeid;
7432
7433 if ($cvalue =~ m/^([^:]+):/) {
7434 $storeid = $1;
7435 }
7436
7437 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
7438
7439 my $res = [];
7440 foreach my $id (keys %$data) {
7441 foreach my $item (@{$data->{$id}}) {
7442 next if $item->{format} !~ m/^vma\.(gz|lzo)$/;
7443 push @$res, $item->{volid} if defined($item->{volid});
7444 }
7445 }
7446
7447 return $res;
7448}
7449
7450my $complete_vmid_full = sub {
7451 my ($running) = @_;
7452
7453 my $idlist = vmstatus();
7454
7455 my $res = [];
7456
7457 foreach my $id (keys %$idlist) {
7458 my $d = $idlist->{$id};
7459 if (defined($running)) {
7460 next if $d->{template};
7461 next if $running && $d->{status} ne 'running';
7462 next if !$running && $d->{status} eq 'running';
7463 }
7464 push @$res, $id;
7465
7466 }
7467 return $res;
7468};
7469
7470sub complete_vmid {
7471 return &$complete_vmid_full();
7472}
7473
7474sub complete_vmid_stopped {
7475 return &$complete_vmid_full(0);
7476}
7477
7478sub complete_vmid_running {
7479 return &$complete_vmid_full(1);
7480}
7481
335af808
DM
7482sub complete_storage {
7483
7484 my $cfg = PVE::Storage::config();
7485 my $ids = $cfg->{ids};
7486
7487 my $res = [];
7488 foreach my $sid (keys %$ids) {
7489 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
c4c844ef 7490 next if !$ids->{$sid}->{content}->{images};
335af808
DM
7491 push @$res, $sid;
7492 }
7493
7494 return $res;
7495}
7496
1e3baf05 74971;