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