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