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