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