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