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