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