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