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