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