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