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