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