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