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