]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
api: add missing index child links
[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++) {
dae0c8e5
TL
3764 my $id = "hostpci$i";
3765 my $d = parse_hostpci($conf->{$id});
2e3b7e2a
AD
3766 next if !$d;
3767
dae0c8e5 3768 if (my $pcie = $d->{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) {
dae0c8e5 3773 $pciaddr = print_pcie_addr("${id}bus0");
739ba340 3774 } else {
c4e16381 3775 # add more root ports if needed, 4 are present by default
dae0c8e5 3776 # by pve-q35 cfgs, rest added here on demand.
c4e16381
AL
3777 if ($i > 3) {
3778 push @$devices, '-device', print_pcie_root_port($i);
3779 }
dae0c8e5 3780 $pciaddr = print_pcie_addr($id);
739ba340 3781 }
bd772c2e 3782 } else {
dae0c8e5 3783 $pciaddr = print_pci_addr($id, $bridges, $arch, $machine_type);
2e3b7e2a
AD
3784 }
3785
1f4f447b
WB
3786 my $xvga = '';
3787 if ($d->{'x-vga'}) {
dae0c8e5 3788 $xvga = ',x-vga=on' if !($conf->{bios} && $conf->{bios} eq 'ovmf');
16a91d65 3789 $kvm_off = 1;
bfc0bb81 3790 $vga->{type} = 'none' if !defined($conf->{vga});
4317f69f 3791 $gpu_passthrough = 1;
137483c0 3792 }
dae0c8e5 3793
4543ecf0
AD
3794 my $pcidevices = $d->{pciid};
3795 my $multifunction = 1 if @$pcidevices > 1;
dae0c8e5 3796
6ab45bd7
DC
3797 my $sysfspath;
3798 if ($d->{mdev} && scalar(@$pcidevices) == 1) {
dae0c8e5 3799 my $pci_id = $pcidevices->[0]->{id};
6ab45bd7 3800 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
dae0c8e5 3801 $sysfspath = "/sys/bus/pci/devices/0000:$pci_id/$uuid";
6ab45bd7 3802 } elsif ($d->{mdev}) {
dae0c8e5 3803 warn "ignoring mediated device '$id' with multifunction device\n";
6ab45bd7 3804 }
2e3b7e2a 3805
4543ecf0 3806 my $j=0;
dae0c8e5 3807 foreach my $pcidevice (@$pcidevices) {
6ab45bd7 3808 my $devicestr = "vfio-pci";
dae0c8e5 3809
6ab45bd7
DC
3810 if ($sysfspath) {
3811 $devicestr .= ",sysfsdev=$sysfspath";
3812 } else {
2fd24788 3813 $devicestr .= ",host=$pcidevice->{id}";
6ab45bd7 3814 }
4543ecf0 3815
dae0c8e5
TL
3816 my $mf_addr = $multifunction ? ".$j" : '';
3817 $devicestr .= ",id=${id}${mf_addr}${pciaddr}${mf_addr}";
3818
3819 if ($j == 0) {
3820 $devicestr .= ',rombar=0' if defined($d->{rombar}) && !$d->{rombar};
3821 $devicestr .= "$xvga";
4543ecf0 3822 $devicestr .= ",multifunction=on" if $multifunction;
dae0c8e5 3823 $devicestr .= ",romfile=/usr/share/kvm/$d->{romfile}" if $d->{romfile};
4543ecf0
AD
3824 }
3825
3826 push @$devices, '-device', $devicestr;
3827 $j++;
3828 }
1e3baf05
DM
3829 }
3830
3831 # usb devices
d40e5e18
DC
3832 my @usbdevices = PVE::QemuServer::USB::get_usb_devices($conf, $usbdesc->{format}, $MAX_USB_DEVICES);
3833 push @$devices, @usbdevices if @usbdevices;
1e3baf05 3834 # serial devices
bae179aa 3835 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
34978be3 3836 if (my $path = $conf->{"serial$i"}) {
9f9d2fb2
DM
3837 if ($path eq 'socket') {
3838 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3839 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
91b01bbb
WB
3840 # On aarch64, serial0 is the UART device. Qemu only allows
3841 # connecting UART devices via the '-serial' command line, as
3842 # the device has a fixed slot on the hardware...
3843 if ($arch eq 'aarch64' && $i == 0) {
3844 push @$devices, '-serial', "chardev:serial$i";
3845 } else {
3846 push @$devices, '-device', "isa-serial,chardev=serial$i";
3847 }
9f9d2fb2
DM
3848 } else {
3849 die "no such serial device\n" if ! -c $path;
3850 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3851 push @$devices, '-device', "isa-serial,chardev=serial$i";
3852 }
34978be3 3853 }
1e3baf05
DM
3854 }
3855
3856 # parallel devices
1989a89c 3857 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
34978be3 3858 if (my $path = $conf->{"parallel$i"}) {
19672434 3859 die "no such parallel device\n" if ! -c $path;
32e69805 3860 my $devtype = $path =~ m!^/dev/usb/lp! ? 'tty' : 'parport';
4c5dbaf6 3861 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
5bdcf937 3862 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
34978be3 3863 }
1e3baf05
DM
3864 }
3865
d5535a00
TL
3866 if (my $audio = conf_has_audio($conf)) {
3867
2e7b5925
AL
3868 my $audiopciaddr = print_pci_addr("audio0", $bridges, $arch, $machine_type);
3869
d5535a00
TL
3870 my $id = $audio->{dev_id};
3871 if ($audio->{dev} eq 'AC97') {
3872 push @$devices, '-device', "AC97,id=${id}${audiopciaddr}";
3873 } elsif ($audio->{dev} =~ /intel\-hda$/) {
3874 push @$devices, '-device', "$audio->{dev},id=${id}${audiopciaddr}";
3875 push @$devices, '-device', "hda-micro,id=${id}-codec0,bus=${id}.0,cad=0";
3876 push @$devices, '-device', "hda-duplex,id=${id}-codec1,bus=${id}.0,cad=1";
b3703d39 3877 } else {
d5535a00 3878 die "unkown audio device '$audio->{dev}', implement me!";
2e7b5925 3879 }
1448547f 3880
d5535a00 3881 push @$devices, '-audiodev', "$audio->{backend},id=$audio->{backend_id}";
2e7b5925 3882 }
19672434 3883
1e3baf05
DM
3884 my $sockets = 1;
3885 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3886 $sockets = $conf->{sockets} if $conf->{sockets};
3887
3888 my $cores = $conf->{cores} || 1;
3bd18e48 3889
de9d1e55 3890 my $maxcpus = $sockets * $cores;
76267728 3891
de9d1e55 3892 my $vcpus = $conf->{vcpus} ? $conf->{vcpus} : $maxcpus;
76267728 3893
de9d1e55
AD
3894 my $allowed_vcpus = $cpuinfo->{cpus};
3895
6965d5d1 3896 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
de9d1e55
AD
3897 if ($allowed_vcpus < $maxcpus);
3898
69c81430 3899 if($hotplug_features->{cpu} && qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 7)) {
1e3baf05 3900
69c81430
AD
3901 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3902 for (my $i = 2; $i <= $vcpus; $i++) {
3903 my $cpustr = print_cpu_device($conf,$i);
3904 push @$cmd, '-device', $cpustr;
3905 }
3906
3907 } else {
3908
3909 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3910 }
1e3baf05
DM
3911 push @$cmd, '-nodefaults';
3912
32baffb4 3913 my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
3b408e82 3914
0888fdce
DM
3915 my $bootindex_hash = {};
3916 my $i = 1;
3917 foreach my $o (split(//, $bootorder)) {
3918 $bootindex_hash->{$o} = $i*100;
3919 $i++;
afdb31d5 3920 }
3b408e82 3921
dbea4415 3922 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
1e3baf05 3923
6b64503e 3924 push @$cmd, '-no-acpi' if defined($conf->{acpi}) && $conf->{acpi} == 0;
1e3baf05 3925
6b64503e 3926 push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
1e3baf05 3927
84902837 3928 if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none'){
d559309f 3929 push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
b7be4ba9 3930 my $socket = vnc_socket($vmid);
dc62a7fa 3931 push @$cmd, '-vnc', "unix:$socket,password";
b7be4ba9 3932 } else {
55655ebc 3933 push @$cmd, '-vga', 'none' if $vga->{type} eq 'none';
b7be4ba9
AD
3934 push @$cmd, '-nographic';
3935 }
3936
1e3baf05 3937 # time drift fix
6b64503e 3938 my $tdf = defined($conf->{tdf}) ? $conf->{tdf} : $defaults->{tdf};
1e3baf05 3939
8c559505 3940 my $useLocaltime = $conf->{localtime};
1e3baf05 3941
4317f69f
AD
3942 if ($winversion >= 5) { # windows
3943 $useLocaltime = 1 if !defined($conf->{localtime});
7a131888 3944
4317f69f
AD
3945 # use time drift fix when acpi is enabled
3946 if (!(defined($conf->{acpi}) && $conf->{acpi} == 0)) {
3947 $tdf = 1 if !defined($conf->{tdf});
462e8d19 3948 }
4317f69f 3949 }
462e8d19 3950
4317f69f
AD
3951 if ($winversion >= 6) {
3952 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3953 push @$cmd, '-no-hpet';
1e3baf05
DM
3954 }
3955
8c559505
DM
3956 push @$rtcFlags, 'driftfix=slew' if $tdf;
3957
74c02ef7 3958 if (!$kvm) {
8c559505 3959 push @$machineFlags, 'accel=tcg';
7f0b5beb 3960 }
1e3baf05 3961
952958bc
DM
3962 if ($machine_type) {
3963 push @$machineFlags, "type=${machine_type}";
3bafc510
DM
3964 }
3965
85f0511d 3966 if (($conf->{startdate}) && ($conf->{startdate} ne 'now')) {
8c559505
DM
3967 push @$rtcFlags, "base=$conf->{startdate}";
3968 } elsif ($useLocaltime) {
3969 push @$rtcFlags, 'base=localtime';
3970 }
1e3baf05 3971
4fc262bd 3972 push @$cmd, get_cpu_options($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
519ed28c 3973
0567a4d5 3974 PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
370b05e7 3975
1e3baf05
DM
3976 push @$cmd, '-S' if $conf->{freeze};
3977
b20df606 3978 push @$cmd, '-k', $conf->{keyboard} if defined($conf->{keyboard});
1e3baf05 3979
9d66b397 3980 if (parse_guest_agent($conf)->{enabled}) {
7a6c2150 3981 my $qgasocket = qmp_socket($vmid, 1);
d559309f 3982 my $pciaddr = print_pci_addr("qga0", $bridges, $arch, $machine_type);
ab6a046f
AD
3983 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3984 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3985 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3986 }
3987
1d794448 3988 my $spice_port;
2fa3151e 3989
590e698c
DM
3990 if ($qxlnum) {
3991 if ($qxlnum > 1) {
ac087616 3992 if ($winversion){
590e698c 3993 for(my $i = 1; $i < $qxlnum; $i++){
d559309f 3994 push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
590e698c
DM
3995 }
3996 } else {
3997 # assume other OS works like Linux
55655ebc
DC
3998 my ($ram, $vram) = ("134217728", "67108864");
3999 if ($vga->{memory}) {
4000 $ram = PVE::Tools::convert_size($qxlnum*4*$vga->{memory}, 'mb' => 'b');
4001 $vram = PVE::Tools::convert_size($qxlnum*2*$vga->{memory}, 'mb' => 'b');
4002 }
4003 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
4004 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
2fa3151e
AD
4005 }
4006 }
4007
d559309f 4008 my $pciaddr = print_pci_addr("spice", $bridges, $arch, $machine_type);
95a4b4a9 4009
af0eba7e
WB
4010 my $nodename = PVE::INotify::nodename();
4011 my $pfamily = PVE::Tools::get_host_address_family($nodename);
91152441
WB
4012 my @nodeaddrs = PVE::Tools::getaddrinfo_all('localhost', family => $pfamily);
4013 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
4014 my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
4015 $spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
943340a6 4016
caab114a
TL
4017 my $spice_enhancement = PVE::JSONSchema::parse_property_string($spice_enhancements_fmt, $conf->{spice_enhancements} // '');
4018 if ($spice_enhancement->{foldersharing}) {
4019 push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
4020 push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
4021 }
c4df18db 4022
caab114a
TL
4023 my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
4024 $spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}" if $spice_enhancement->{videostreaming};
4025 push @$devices, '-spice', "$spice_opts";
1011b570 4026
d2da6d9b
AD
4027 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
4028 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
4029 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
c4df18db 4030
1011b570
DM
4031 }
4032
8d9ae0d2
DM
4033 # enable balloon by default, unless explicitly disabled
4034 if (!defined($conf->{balloon}) || $conf->{balloon}) {
d559309f 4035 $pciaddr = print_pci_addr("balloon0", $bridges, $arch, $machine_type);
8d9ae0d2
DM
4036 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
4037 }
1e3baf05 4038
0ea9541d
DM
4039 if ($conf->{watchdog}) {
4040 my $wdopts = parse_watchdog($conf->{watchdog});
d559309f 4041 $pciaddr = print_pci_addr("watchdog", $bridges, $arch, $machine_type);
0a40e8ea 4042 my $watchdog = $wdopts->{model} || 'i6300esb';
5bdcf937
AD
4043 push @$devices, '-device', "$watchdog$pciaddr";
4044 push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
0ea9541d
DM
4045 }
4046
1e3baf05 4047 my $vollist = [];
941e0c42 4048 my $scsicontroller = {};
26ee04b6 4049 my $ahcicontroller = {};
cdd20088 4050 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : $defaults->{scsihw};
1e3baf05 4051
5881b913
DM
4052 # Add iscsi initiator name if available
4053 if (my $initiator = get_initiator_name()) {
4054 push @$devices, '-iscsi', "initiator-name=$initiator";
4055 }
4056
1e3baf05
DM
4057 foreach_drive($conf, sub {
4058 my ($ds, $drive) = @_;
4059
ff1a2432 4060 if (PVE::Storage::parse_volume_id($drive->{file}, 1)) {
1e3baf05 4061 push @$vollist, $drive->{file};
ff1a2432 4062 }
afdb31d5 4063
4dcce9ee
TL
4064 # ignore efidisk here, already added in bios/fw handling code above
4065 return if $drive->{interface} eq 'efidisk';
4066
1e3baf05 4067 $use_virtio = 1 if $ds =~ m/^virtio/;
3b408e82
DM
4068
4069 if (drive_is_cdrom ($drive)) {
4070 if ($bootindex_hash->{d}) {
4071 $drive->{bootindex} = $bootindex_hash->{d};
4072 $bootindex_hash->{d} += 1;
4073 }
4074 } else {
4075 if ($bootindex_hash->{c}) {
4076 $drive->{bootindex} = $bootindex_hash->{c} if $conf->{bootdisk} && ($conf->{bootdisk} eq $ds);
4077 $bootindex_hash->{c} += 1;
4078 }
4079 }
4080
51f492cd
AD
4081 if($drive->{interface} eq 'virtio'){
4082 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread};
4083 }
4084
941e0c42 4085 if ($drive->{interface} eq 'scsi') {
cdd20088 4086
ee034f5c 4087 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
6731a4cf 4088
d559309f 4089 $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $machine_type);
a1b7d579 4090 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
fc8b40fd
AD
4091
4092 my $iothread = '';
4093 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{iothread}){
4094 $iothread .= ",iothread=iothread-$controller_prefix$controller";
4095 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
e7a5104d
DC
4096 } elsif ($drive->{iothread}) {
4097 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
fc8b40fd
AD
4098 }
4099
6e11f143
AD
4100 my $queues = '';
4101 if($conf->{scsihw} && $conf->{scsihw} eq "virtio-scsi-single" && $drive->{queues}){
4102 $queues = ",num_queues=$drive->{queues}";
370b05e7 4103 }
6e11f143
AD
4104
4105 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
cdd20088 4106 $scsicontroller->{$controller}=1;
941e0c42 4107 }
3b408e82 4108
26ee04b6
DA
4109 if ($drive->{interface} eq 'sata') {
4110 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
d559309f 4111 $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
5bdcf937 4112 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
26ee04b6
DA
4113 $ahcicontroller->{$controller}=1;
4114 }
46f58b5f 4115
15b21acc
MR
4116 my $drive_cmd = print_drive_full($storecfg, $vmid, $drive);
4117 push @$devices, '-drive',$drive_cmd;
d559309f 4118 push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
1e3baf05
DM
4119 });
4120
cc4d6182 4121 for (my $i = 0; $i < $MAX_NETS; $i++) {
5f0c4c32 4122 next if !$conf->{"net$i"};
cc4d6182
DA
4123 my $d = parse_net($conf->{"net$i"});
4124 next if !$d;
1e3baf05 4125
cc4d6182 4126 $use_virtio = 1 if $d->{model} eq 'virtio';
1e3baf05 4127
cc4d6182
DA
4128 if ($bootindex_hash->{n}) {
4129 $d->{bootindex} = $bootindex_hash->{n};
4130 $bootindex_hash->{n} += 1;
4131 }
1e3baf05 4132
d559309f 4133 my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, "net$i");
5bdcf937
AD
4134 push @$devices, '-netdev', $netdevfull;
4135
d559309f 4136 my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
5bdcf937
AD
4137 push @$devices, '-device', $netdevicefull;
4138 }
1e3baf05 4139
6dbcb073
DC
4140 if ($conf->{ivshmem}) {
4141 my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
e3c27a6a 4142
6dbcb073
DC
4143 my $bus;
4144 if ($q35) {
4145 $bus = print_pcie_addr("ivshmem");
4146 } else {
4147 $bus = print_pci_addr("ivshmem", $bridges, $arch, $machine_type);
4148 }
e3c27a6a
TL
4149
4150 my $ivshmem_name = $ivshmem->{name} // $vmid;
4151 my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
4152
6dbcb073
DC
4153 push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
4154 push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
4155 }
4156
db656e5f
DM
4157 if (!$q35) {
4158 # add pci bridges
fc79e813
AD
4159 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
4160 $bridges->{1} = 1;
4161 $bridges->{2} = 1;
4162 }
4163
6731a4cf
AD
4164 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
4165
f8e83f05 4166 while (my ($k, $v) = each %$bridges) {
d559309f 4167 $pciaddr = print_pci_addr("pci.$k", undef, $arch, $machine_type);
f8e83f05
AD
4168 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
4169 }
19672434
DM
4170 }
4171
5bdcf937 4172 push @$cmd, @$devices;
be190583 4173 push @$cmd, '-rtc', join(',', @$rtcFlags)
8c559505 4174 if scalar(@$rtcFlags);
be190583 4175 push @$cmd, '-machine', join(',', @$machineFlags)
8c559505
DM
4176 if scalar(@$machineFlags);
4177 push @$cmd, '-global', join(',', @$globalFlags)
4178 if scalar(@$globalFlags);
4179
7ceade4c
DC
4180 if (my $vmstate = $conf->{vmstate}) {
4181 my $statepath = PVE::Storage::path($storecfg, $vmstate);
4182 PVE::Storage::activate_volumes($storecfg, [$vmstate]);
4183 push @$cmd, '-loadstate', $statepath;
4184 }
4185
76350670
DC
4186 # add custom args
4187 if ($conf->{args}) {
4188 my $aa = PVE::Tools::split_args($conf->{args});
4189 push @$cmd, @$aa;
4190 }
4191
1d794448 4192 return wantarray ? ($cmd, $vollist, $spice_port) : $cmd;
1e3baf05 4193}
19672434 4194
1e3baf05
DM
4195sub vnc_socket {
4196 my ($vmid) = @_;
4197 return "${var_run_tmpdir}/$vmid.vnc";
4198}
4199
943340a6 4200sub spice_port {
1011b570 4201 my ($vmid) = @_;
943340a6 4202
1d794448 4203 my $res = vm_mon_cmd($vmid, 'query-spice');
943340a6
DM
4204
4205 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
1011b570
DM
4206}
4207
c971c4f2 4208sub qmp_socket {
71bd73b5 4209 my ($vmid, $qga, $name) = @_;
693d12a2 4210 my $sockettype = $qga ? 'qga' : 'qmp';
71bd73b5
DC
4211 my $ext = $name ? '-'.$name : '';
4212 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
c971c4f2
AD
4213}
4214
1e3baf05
DM
4215sub pidfile_name {
4216 my ($vmid) = @_;
4217 return "${var_run_tmpdir}/$vmid.pid";
4218}
4219
86fdcfb2
DA
4220sub vm_devices_list {
4221 my ($vmid) = @_;
4222
ceea9078 4223 my $res = vm_mon_cmd($vmid, 'query-pci');
f721624b 4224 my $devices_to_check = [];
ceea9078
DM
4225 my $devices = {};
4226 foreach my $pcibus (@$res) {
f721624b
DC
4227 push @$devices_to_check, @{$pcibus->{devices}},
4228 }
4229
4230 while (@$devices_to_check) {
4231 my $to_check = [];
4232 for my $d (@$devices_to_check) {
4233 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
4234 next if !$d->{'pci_bridge'};
4235
4236 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices}});
4237 push @$to_check, @{$d->{'pci_bridge'}->{devices}};
f78cc802 4238 }
f721624b 4239 $devices_to_check = $to_check;
f78cc802
AD
4240 }
4241
4242 my $resblock = vm_mon_cmd($vmid, 'query-block');
4243 foreach my $block (@$resblock) {
4244 if($block->{device} =~ m/^drive-(\S+)/){
4245 $devices->{$1} = 1;
1dc4f496
DM
4246 }
4247 }
86fdcfb2 4248
3d7389fe
DM
4249 my $resmice = vm_mon_cmd($vmid, 'query-mice');
4250 foreach my $mice (@$resmice) {
4251 if ($mice->{name} eq 'QEMU HID Tablet') {
4252 $devices->{tablet} = 1;
4253 last;
4254 }
4255 }
4256
deb091c5
DC
4257 # for usb devices there is no query-usb
4258 # but we can iterate over the entries in
4259 # qom-list path=/machine/peripheral
4260 my $resperipheral = vm_mon_cmd($vmid, 'qom-list', path => '/machine/peripheral');
4261 foreach my $per (@$resperipheral) {
4262 if ($per->{name} =~ m/^usb\d+$/) {
4263 $devices->{$per->{name}} = 1;
4264 }
4265 }
4266
1dc4f496 4267 return $devices;
86fdcfb2
DA
4268}
4269
ec21aa11 4270sub vm_deviceplug {
d559309f 4271 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
ae57f6b3 4272
db656e5f
DM
4273 my $q35 = machine_type_is_q35($conf);
4274
95d6343b
DA
4275 my $devices_list = vm_devices_list($vmid);
4276 return 1 if defined($devices_list->{$deviceid});
4277
d559309f 4278 qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
fee46675 4279
3d7389fe 4280 if ($deviceid eq 'tablet') {
fee46675 4281
d559309f
WB
4282 qemu_deviceadd($vmid, print_tabletdevice_full($conf, $arch));
4283
4284 } elsif ($deviceid eq 'keyboard') {
4285
4286 qemu_deviceadd($vmid, print_keyboarddevice_full($conf, $arch));
3d7389fe 4287
4eb68604
DC
4288 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4289
f745762b
DC
4290 die "usb hotplug currently not reliable\n";
4291 # since we can't reliably hot unplug all added usb devices
4292 # and usb passthrough disables live migration
4293 # we disable usb hotplugging for now
4eb68604
DC
4294 qemu_deviceadd($vmid, PVE::QemuServer::USB::print_usbdevice_full($conf, $deviceid, $device));
4295
fee46675 4296 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
40f28a9f 4297
22de899a
AD
4298 qemu_iothread_add($vmid, $deviceid, $device);
4299
fee46675 4300 qemu_driveadd($storecfg, $vmid, $device);
d559309f 4301 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $machine_type);
fee46675 4302
5e5dcb73 4303 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
4304 eval { qemu_deviceaddverify($vmid, $deviceid); };
4305 if (my $err = $@) {
63c2da2f
DM
4306 eval { qemu_drivedel($vmid, $deviceid); };
4307 warn $@ if $@;
fee46675 4308 die $err;
5e5dcb73 4309 }
cfc817c7 4310
2733141c 4311 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
fee46675 4312
fc8b40fd 4313
cdd20088 4314 my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
d559309f 4315 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
a1b7d579 4316 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
2733141c
AD
4317
4318 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
fee46675 4319
fc8b40fd
AD
4320 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread}) {
4321 qemu_iothread_add($vmid, $deviceid, $device);
4322 $devicefull .= ",iothread=iothread-$deviceid";
4323 }
4324
6e11f143
AD
4325 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues}) {
4326 $devicefull .= ",num_queues=$device->{queues}";
4327 }
4328
cfc817c7 4329 qemu_deviceadd($vmid, $devicefull);
fee46675 4330 qemu_deviceaddverify($vmid, $deviceid);
cfc817c7 4331
fee46675
DM
4332 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4333
d559309f 4334 qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device, $arch, $machine_type);
fee46675 4335 qemu_driveadd($storecfg, $vmid, $device);
a1b7d579 4336
d559309f 4337 my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $machine_type);
fee46675
DM
4338 eval { qemu_deviceadd($vmid, $devicefull); };
4339 if (my $err = $@) {
63c2da2f
DM
4340 eval { qemu_drivedel($vmid, $deviceid); };
4341 warn $@ if $@;
fee46675 4342 die $err;
a4f091a0 4343 }
a4f091a0 4344
fee46675
DM
4345 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4346
95d3be58 4347 return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
8718099c 4348
95d3be58
DC
4349 my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf);
4350 my $use_old_bios_files = undef;
4351 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
8718099c 4352
95d3be58
DC
4353 my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4354 qemu_deviceadd($vmid, $netdevicefull);
79046fd1
DC
4355 eval {
4356 qemu_deviceaddverify($vmid, $deviceid);
4357 qemu_set_link_status($vmid, $deviceid, !$device->{link_down});
4358 };
fee46675
DM
4359 if (my $err = $@) {
4360 eval { qemu_netdevdel($vmid, $deviceid); };
4361 warn $@ if $@;
4362 die $err;
95d3be58 4363 }
2630d2a9 4364
fee46675 4365 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
b467f79a 4366
40f28a9f 4367 my $bridgeid = $2;
d559309f 4368 my $pciaddr = print_pci_addr($deviceid, undef, $arch, $machine_type);
40f28a9f 4369 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
a1b7d579 4370
40f28a9f 4371 qemu_deviceadd($vmid, $devicefull);
fee46675
DM
4372 qemu_deviceaddverify($vmid, $deviceid);
4373
4374 } else {
a1b7d579 4375 die "can't hotplug device '$deviceid'\n";
40f28a9f
AD
4376 }
4377
5e5dcb73 4378 return 1;
a4dea331
DA
4379}
4380
3eec5767 4381# fixme: this should raise exceptions on error!
ec21aa11 4382sub vm_deviceunplug {
f19d1c47 4383 my ($vmid, $conf, $deviceid) = @_;
873c2d69 4384
95d6343b
DA
4385 my $devices_list = vm_devices_list($vmid);
4386 return 1 if !defined($devices_list->{$deviceid});
4387
63c2da2f
DM
4388 die "can't unplug bootdisk" if $conf->{bootdisk} && $conf->{bootdisk} eq $deviceid;
4389
d559309f 4390 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
63c2da2f 4391
3d7389fe 4392 qemu_devicedel($vmid, $deviceid);
3d7389fe 4393
4eb68604
DC
4394 } elsif ($deviceid =~ m/^usb\d+$/) {
4395
f745762b
DC
4396 die "usb hotplug currently not reliable\n";
4397 # when unplugging usb devices this way,
4398 # there may be remaining usb controllers/hubs
4399 # so we disable it for now
4eb68604
DC
4400 qemu_devicedel($vmid, $deviceid);
4401 qemu_devicedelverify($vmid, $deviceid);
4402
63c2da2f 4403 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
f19d1c47 4404
5e5dcb73 4405 qemu_devicedel($vmid, $deviceid);
63c2da2f
DM
4406 qemu_devicedelverify($vmid, $deviceid);
4407 qemu_drivedel($vmid, $deviceid);
22de899a
AD
4408 qemu_iothread_del($conf, $vmid, $deviceid);
4409
2733141c 4410 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
a1b7d579 4411
63c2da2f 4412 qemu_devicedel($vmid, $deviceid);
8ce30dde 4413 qemu_devicedelverify($vmid, $deviceid);
fc8b40fd 4414 qemu_iothread_del($conf, $vmid, $deviceid);
a1b7d579 4415
63c2da2f 4416 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
cfc817c7 4417
63c2da2f
DM
4418 qemu_devicedel($vmid, $deviceid);
4419 qemu_drivedel($vmid, $deviceid);
a1b7d579 4420 qemu_deletescsihw($conf, $vmid, $deviceid);
8ce30dde 4421
63c2da2f 4422 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
a4f091a0 4423
2630d2a9 4424 qemu_devicedel($vmid, $deviceid);
63c2da2f
DM
4425 qemu_devicedelverify($vmid, $deviceid);
4426 qemu_netdevdel($vmid, $deviceid);
4427
4428 } else {
4429 die "can't unplug device '$deviceid'\n";
2630d2a9
DA
4430 }
4431
5e5dcb73
DA
4432 return 1;
4433}
4434
4435sub qemu_deviceadd {
4436 my ($vmid, $devicefull) = @_;
873c2d69 4437
d695b5b7
AD
4438 $devicefull = "driver=".$devicefull;
4439 my %options = split(/[=,]/, $devicefull);
f19d1c47 4440
d695b5b7 4441 vm_mon_cmd($vmid, "device_add" , %options);
5e5dcb73 4442}
afdb31d5 4443
5e5dcb73 4444sub qemu_devicedel {
fee46675 4445 my ($vmid, $deviceid) = @_;
63c2da2f 4446
5a77d8c1 4447 my $ret = vm_mon_cmd($vmid, "device_del", id => $deviceid);
5e5dcb73
DA
4448}
4449
22de899a
AD
4450sub qemu_iothread_add {
4451 my($vmid, $deviceid, $device) = @_;
4452
4453 if ($device->{iothread}) {
4454 my $iothreads = vm_iothreads_list($vmid);
4455 qemu_objectadd($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4456 }
4457}
4458
4459sub qemu_iothread_del {
4460 my($conf, $vmid, $deviceid) = @_;
4461
7820eae4
DC
4462 my $confid = $deviceid;
4463 if ($deviceid =~ m/^(?:virtioscsi|scsihw)(\d+)$/) {
4464 $confid = 'scsi' . $1;
4465 }
4466 my $device = parse_drive($confid, $conf->{$confid});
22de899a
AD
4467 if ($device->{iothread}) {
4468 my $iothreads = vm_iothreads_list($vmid);
4469 qemu_objectdel($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4470 }
4471}
4472
4d3f29ed
AD
4473sub qemu_objectadd {
4474 my($vmid, $objectid, $qomtype) = @_;
4475
4476 vm_mon_cmd($vmid, "object-add", id => $objectid, "qom-type" => $qomtype);
4477
4478 return 1;
4479}
4480
4481sub qemu_objectdel {
4482 my($vmid, $objectid) = @_;
4483
4484 vm_mon_cmd($vmid, "object-del", id => $objectid);
4485
4486 return 1;
4487}
4488
5e5dcb73 4489sub qemu_driveadd {
fee46675 4490 my ($storecfg, $vmid, $device) = @_;
5e5dcb73
DA
4491
4492 my $drive = print_drive_full($storecfg, $vmid, $device);
7a69fc3c 4493 $drive =~ s/\\/\\\\/g;
8ead5ec7 4494 my $ret = vm_human_monitor_command($vmid, "drive_add auto \"$drive\"");
fee46675 4495
5e5dcb73 4496 # If the command succeeds qemu prints: "OK"
fee46675
DM
4497 return 1 if $ret =~ m/OK/s;
4498
4499 die "adding drive failed: $ret\n";
5e5dcb73 4500}
afdb31d5 4501
5e5dcb73
DA
4502sub qemu_drivedel {
4503 my($vmid, $deviceid) = @_;
873c2d69 4504
7b7c6d1b 4505 my $ret = vm_human_monitor_command($vmid, "drive_del drive-$deviceid");
5e5dcb73 4506 $ret =~ s/^\s+//;
a1b7d579 4507
63c2da2f 4508 return 1 if $ret eq "";
a1b7d579 4509
63c2da2f 4510 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
a1b7d579
DM
4511 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4512
63c2da2f 4513 die "deleting drive $deviceid failed : $ret\n";
5e5dcb73 4514}
f19d1c47 4515
5e5dcb73 4516sub qemu_deviceaddverify {
fee46675 4517 my ($vmid, $deviceid) = @_;
873c2d69 4518
5e5dcb73
DA
4519 for (my $i = 0; $i <= 5; $i++) {
4520 my $devices_list = vm_devices_list($vmid);
4521 return 1 if defined($devices_list->{$deviceid});
4522 sleep 1;
afdb31d5 4523 }
fee46675
DM
4524
4525 die "error on hotplug device '$deviceid'\n";
5e5dcb73 4526}
afdb31d5 4527
5e5dcb73
DA
4528
4529sub qemu_devicedelverify {
63c2da2f
DM
4530 my ($vmid, $deviceid) = @_;
4531
a1b7d579 4532 # need to verify that the device is correctly removed as device_del
63c2da2f 4533 # is async and empty return is not reliable
5e5dcb73 4534
5e5dcb73
DA
4535 for (my $i = 0; $i <= 5; $i++) {
4536 my $devices_list = vm_devices_list($vmid);
4537 return 1 if !defined($devices_list->{$deviceid});
4538 sleep 1;
afdb31d5 4539 }
63c2da2f
DM
4540
4541 die "error on hot-unplugging device '$deviceid'\n";
873c2d69
DA
4542}
4543
cdd20088 4544sub qemu_findorcreatescsihw {
d559309f 4545 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
cfc817c7 4546
ee034f5c 4547 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
2733141c
AD
4548
4549 my $scsihwid="$controller_prefix$controller";
cfc817c7
DA
4550 my $devices_list = vm_devices_list($vmid);
4551
cdd20088 4552 if(!defined($devices_list->{$scsihwid})) {
d559309f 4553 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
cfc817c7 4554 }
fee46675 4555
cfc817c7
DA
4556 return 1;
4557}
4558
8ce30dde
AD
4559sub qemu_deletescsihw {
4560 my ($conf, $vmid, $opt) = @_;
4561
4562 my $device = parse_drive($opt, $conf->{$opt});
4563
a1511b3c 4564 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
2733141c
AD
4565 vm_deviceunplug($vmid, $conf, "virtioscsi$device->{index}");
4566 return 1;
4567 }
4568
ee034f5c 4569 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
8ce30dde
AD
4570
4571 my $devices_list = vm_devices_list($vmid);
4572 foreach my $opt (keys %{$devices_list}) {
74479ee9 4573 if (PVE::QemuServer::is_valid_drivename($opt)) {
8ce30dde
AD
4574 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4575 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4576 return 1;
4577 }
4578 }
4579 }
4580
4581 my $scsihwid="scsihw$controller";
4582
4583 vm_deviceunplug($vmid, $conf, $scsihwid);
4584
4585 return 1;
4586}
4587
281fedb3 4588sub qemu_add_pci_bridge {
d559309f 4589 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
40f28a9f
AD
4590
4591 my $bridges = {};
281fedb3
DM
4592
4593 my $bridgeid;
4594
d559309f 4595 print_pci_addr($device, $bridges, $arch, $machine_type);
40f28a9f
AD
4596
4597 while (my ($k, $v) = each %$bridges) {
4598 $bridgeid = $k;
4599 }
fee46675 4600 return 1 if !defined($bridgeid) || $bridgeid < 1;
281fedb3 4601
40f28a9f
AD
4602 my $bridge = "pci.$bridgeid";
4603 my $devices_list = vm_devices_list($vmid);
4604
281fedb3 4605 if (!defined($devices_list->{$bridge})) {
d559309f 4606 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
40f28a9f 4607 }
281fedb3 4608
40f28a9f
AD
4609 return 1;
4610}
4611
25088687
DM
4612sub qemu_set_link_status {
4613 my ($vmid, $device, $up) = @_;
4614
a1b7d579 4615 vm_mon_cmd($vmid, "set_link", name => $device,
25088687
DM
4616 up => $up ? JSON::true : JSON::false);
4617}
4618
2630d2a9 4619sub qemu_netdevadd {
d559309f 4620 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
2630d2a9 4621
d559309f 4622 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
73aa03b8 4623 my %options = split(/[=,]/, $netdev);
2630d2a9 4624
73aa03b8
AD
4625 vm_mon_cmd($vmid, "netdev_add", %options);
4626 return 1;
2630d2a9
DA
4627}
4628
4629sub qemu_netdevdel {
4630 my ($vmid, $deviceid) = @_;
4631
89c1e0f4 4632 vm_mon_cmd($vmid, "netdev_del", id => $deviceid);
2630d2a9
DA
4633}
4634
16521d63 4635sub qemu_usb_hotplug {
d559309f 4636 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
16521d63
DC
4637
4638 return if !$device;
4639
4640 # remove the old one first
4641 vm_deviceunplug($vmid, $conf, $deviceid);
4642
4643 # check if xhci controller is necessary and available
4644 if ($device->{usb3}) {
4645
4646 my $devicelist = vm_devices_list($vmid);
4647
4648 if (!$devicelist->{xhci}) {
d559309f 4649 my $pciaddr = print_pci_addr("xhci", undef, $arch, $machine_type);
16521d63
DC
4650 qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
4651 }
4652 }
4653 my $d = parse_usb_device($device->{host});
4654 $d->{usb3} = $device->{usb3};
4655
4656 # add the new one
d559309f 4657 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
16521d63
DC
4658}
4659
838776ab 4660sub qemu_cpu_hotplug {
8edc9c08 4661 my ($vmid, $conf, $vcpus) = @_;
838776ab 4662
1e881b75
AD
4663 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4664
8edc9c08
AD
4665 my $sockets = 1;
4666 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4667 $sockets = $conf->{sockets} if $conf->{sockets};
4668 my $cores = $conf->{cores} || 1;
4669 my $maxcpus = $sockets * $cores;
838776ab 4670
8edc9c08 4671 $vcpus = $maxcpus if !$vcpus;
3a11fadb 4672
8edc9c08
AD
4673 die "you can't add more vcpus than maxcpus\n"
4674 if $vcpus > $maxcpus;
3a11fadb 4675
8edc9c08 4676 my $currentvcpus = $conf->{vcpus} || $maxcpus;
1e881b75 4677
eba3e64d 4678 if ($vcpus < $currentvcpus) {
1e881b75
AD
4679
4680 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4681
4682 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4683 qemu_devicedel($vmid, "cpu$i");
4684 my $retry = 0;
4685 my $currentrunningvcpus = undef;
4686 while (1) {
4687 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4688 last if scalar(@{$currentrunningvcpus}) == $i-1;
961af8a3 4689 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
1e881b75
AD
4690 $retry++;
4691 sleep 1;
4692 }
4693 #update conf after each succesfull cpu unplug
4694 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4695 PVE::QemuConfig->write_config($vmid, $conf);
4696 }
4697 } else {
961af8a3 4698 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
1e881b75
AD
4699 }
4700
4701 return;
4702 }
838776ab 4703
8edc9c08 4704 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
961af8a3 4705 die "vcpus in running vm does not match its configuration\n"
8edc9c08 4706 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
838776ab 4707
eba3e64d
AD
4708 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4709
4710 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4711 my $cpustr = print_cpu_device($conf, $i);
4712 qemu_deviceadd($vmid, $cpustr);
4713
4714 my $retry = 0;
4715 my $currentrunningvcpus = undef;
4716 while (1) {
4717 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4718 last if scalar(@{$currentrunningvcpus}) == $i;
961af8a3 4719 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
eba3e64d
AD
4720 sleep 1;
4721 $retry++;
4722 }
4723 #update conf after each succesfull cpu hotplug
4724 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4725 PVE::QemuConfig->write_config($vmid, $conf);
4726 }
4727 } else {
4728
4729 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4730 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4731 }
838776ab
AD
4732 }
4733}
4734
affd2f88 4735sub qemu_block_set_io_throttle {
277ca170
WB
4736 my ($vmid, $deviceid,
4737 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
9196a8ec
WB
4738 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4739 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4740 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
affd2f88 4741
f3f323a3
AD
4742 return if !check_running($vmid) ;
4743
277ca170
WB
4744 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4745 bps => int($bps),
4746 bps_rd => int($bps_rd),
4747 bps_wr => int($bps_wr),
4748 iops => int($iops),
4749 iops_rd => int($iops_rd),
4750 iops_wr => int($iops_wr),
4751 bps_max => int($bps_max),
4752 bps_rd_max => int($bps_rd_max),
4753 bps_wr_max => int($bps_wr_max),
4754 iops_max => int($iops_max),
4755 iops_rd_max => int($iops_rd_max),
9196a8ec
WB
4756 iops_wr_max => int($iops_wr_max),
4757 bps_max_length => int($bps_max_length),
4758 bps_rd_max_length => int($bps_rd_max_length),
4759 bps_wr_max_length => int($bps_wr_max_length),
4760 iops_max_length => int($iops_max_length),
4761 iops_rd_max_length => int($iops_rd_max_length),
4762 iops_wr_max_length => int($iops_wr_max_length),
277ca170 4763 );
f3f323a3 4764
affd2f88
AD
4765}
4766
f5eb281a 4767# old code, only used to shutdown old VM after update
dab36e1e
DM
4768sub __read_avail {
4769 my ($fh, $timeout) = @_;
4770
4771 my $sel = new IO::Select;
4772 $sel->add($fh);
4773
4774 my $res = '';
4775 my $buf;
4776
4777 my @ready;
4778 while (scalar (@ready = $sel->can_read($timeout))) {
4779 my $count;
4780 if ($count = $fh->sysread($buf, 8192)) {
4781 if ($buf =~ /^(.*)\(qemu\) $/s) {
4782 $res .= $1;
4783 last;
4784 } else {
4785 $res .= $buf;
4786 }
4787 } else {
4788 if (!defined($count)) {
4789 die "$!\n";
4790 }
4791 last;
4792 }
4793 }
4794
4795 die "monitor read timeout\n" if !scalar(@ready);
f5eb281a 4796
dab36e1e
DM
4797 return $res;
4798}
4799
c1175c92
AD
4800sub qemu_block_resize {
4801 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4802
ed221350 4803 my $running = check_running($vmid);
c1175c92 4804
7246e8f9 4805 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
c1175c92
AD
4806
4807 return if !$running;
4808
4809 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4810
4811}
4812
1ab0057c
AD
4813sub qemu_volume_snapshot {
4814 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4815
ed221350 4816 my $running = check_running($vmid);
1ab0057c 4817
e5eaa028 4818 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
eba2b721 4819 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync', device => $deviceid, name => $snap);
e5eaa028
WL
4820 } else {
4821 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4822 }
1ab0057c
AD
4823}
4824
fc46aff9
AD
4825sub qemu_volume_snapshot_delete {
4826 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4827
ed221350 4828 my $running = check_running($vmid);
fc46aff9 4829
a2f1554b
AD
4830 if($running) {
4831
4832 $running = undef;
4833 my $conf = PVE::QemuConfig->load_config($vmid);
4834 foreach_drive($conf, sub {
4835 my ($ds, $drive) = @_;
4836 $running = 1 if $drive->{file} eq $volid;
4837 });
4838 }
4839
1ef7592f 4840 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
eba2b721 4841 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync', device => $deviceid, name => $snap);
1ef7592f
AD
4842 } else {
4843 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4844 }
fc46aff9
AD
4845}
4846
264e519f
DM
4847sub set_migration_caps {
4848 my ($vmid) = @_;
a89fded1 4849
8b8345f3 4850 my $cap_ref = [];
a89fded1
AD
4851
4852 my $enabled_cap = {
8b8345f3 4853 "auto-converge" => 1,
0b0a47e8 4854 "xbzrle" => 1,
8b8345f3
DM
4855 "x-rdma-pin-all" => 0,
4856 "zero-blocks" => 0,
b62532e4 4857 "compress" => 0
a89fded1
AD
4858 };
4859
8b8345f3 4860 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
a89fded1 4861
8b8345f3 4862 for my $supported_capability (@$supported_capabilities) {
b463a3ce
SP
4863 push @$cap_ref, {
4864 capability => $supported_capability->{capability},
22430fa2
DM
4865 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4866 };
a89fded1
AD
4867 }
4868
8b8345f3
DM
4869 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4870}
a89fded1 4871
81d95ae1 4872my $fast_plug_option = {
7498eb64 4873 'lock' => 1,
81d95ae1 4874 'name' => 1,
a1b7d579 4875 'onboot' => 1,
81d95ae1
DM
4876 'shares' => 1,
4877 'startup' => 1,
b0ec896e 4878 'description' => 1,
ec647db4 4879 'protection' => 1,
8cad5e9b 4880 'vmstatestorage' => 1,
9e784b11 4881 'hookscript' => 1,
81d95ae1
DM
4882};
4883
3a11fadb
DM
4884# hotplug changes in [PENDING]
4885# $selection hash can be used to only apply specified options, for
4886# example: { cores => 1 } (only apply changed 'cores')
4887# $errors ref is used to return error messages
c427973b 4888sub vmconfig_hotplug_pending {
3a11fadb 4889 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
c427973b 4890
8e90138a 4891 my $defaults = load_defaults();
d559309f 4892 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
c427973b
DM
4893
4894 # commit values which do not have any impact on running VM first
3a11fadb
DM
4895 # Note: those option cannot raise errors, we we do not care about
4896 # $selection and always apply them.
4897
4898 my $add_error = sub {
4899 my ($opt, $msg) = @_;
4900 $errors->{$opt} = "hotplug problem - $msg";
4901 };
c427973b
DM
4902
4903 my $changes = 0;
4904 foreach my $opt (keys %{$conf->{pending}}) { # add/change
81d95ae1 4905 if ($fast_plug_option->{$opt}) {
c427973b
DM
4906 $conf->{$opt} = $conf->{pending}->{$opt};
4907 delete $conf->{pending}->{$opt};
4908 $changes = 1;
4909 }
4910 }
4911
4912 if ($changes) {
ffda963f
FG
4913 PVE::QemuConfig->write_config($vmid, $conf);
4914 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
c427973b
DM
4915 }
4916
b3c2bdd1 4917 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
c427973b 4918
3dc38fbb
WB
4919 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4920 while (my ($opt, $force) = each %$pending_delete_hash) {
3a11fadb 4921 next if $selection && !$selection->{$opt};
3a11fadb 4922 eval {
51a6f637
AD
4923 if ($opt eq 'hotplug') {
4924 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4925 } elsif ($opt eq 'tablet') {
b3c2bdd1 4926 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 4927 if ($defaults->{tablet}) {
d559309f
WB
4928 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
4929 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
4930 if $arch eq 'aarch64';
3a11fadb 4931 } else {
d559309f
WB
4932 vm_deviceunplug($vmid, $conf, 'tablet');
4933 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 4934 }
4eb68604 4935 } elsif ($opt =~ m/^usb\d+/) {
f745762b
DC
4936 die "skip\n";
4937 # since we cannot reliably hot unplug usb devices
4938 # we are disabling it
4eb68604
DC
4939 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4940 vm_deviceunplug($vmid, $conf, $opt);
8edc9c08 4941 } elsif ($opt eq 'vcpus') {
b3c2bdd1 4942 die "skip\n" if !$hotplug_features->{cpu};
8edc9c08 4943 qemu_cpu_hotplug($vmid, $conf, undef);
9c2f7069 4944 } elsif ($opt eq 'balloon') {
81d95ae1 4945 # enable balloon device is not hotpluggable
75b51053
DC
4946 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4947 # here we reset the ballooning value to memory
4948 my $balloon = $conf->{memory} || $defaults->{memory};
4949 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
81d95ae1
DM
4950 } elsif ($fast_plug_option->{$opt}) {
4951 # do nothing
3eec5767 4952 } elsif ($opt =~ m/^net(\d+)$/) {
b3c2bdd1 4953 die "skip\n" if !$hotplug_features->{network};
3eec5767 4954 vm_deviceunplug($vmid, $conf, $opt);
74479ee9 4955 } elsif (is_valid_drivename($opt)) {
b3c2bdd1 4956 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
19120f99 4957 vm_deviceunplug($vmid, $conf, $opt);
3dc38fbb 4958 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4d3f29ed
AD
4959 } elsif ($opt =~ m/^memory$/) {
4960 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 4961 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
c8effec3
AD
4962 } elsif ($opt eq 'cpuunits') {
4963 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
58be00f1
AD
4964 } elsif ($opt eq 'cpulimit') {
4965 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
3d7389fe 4966 } else {
e56beeda 4967 die "skip\n";
3d7389fe 4968 }
3a11fadb
DM
4969 };
4970 if (my $err = $@) {
e56beeda
DM
4971 &$add_error($opt, $err) if $err ne "skip\n";
4972 } else {
3a11fadb
DM
4973 # save new config if hotplug was successful
4974 delete $conf->{$opt};
4975 vmconfig_undelete_pending_option($conf, $opt);
ffda963f
FG
4976 PVE::QemuConfig->write_config($vmid, $conf);
4977 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
3d7389fe 4978 }
3d7389fe
DM
4979 }
4980
9ed7a77c
WB
4981 my $apply_pending_cloudinit;
4982 $apply_pending_cloudinit = sub {
4983 my ($key, $value) = @_;
4984 $apply_pending_cloudinit = sub {}; # once is enough
4985
4986 my @cloudinit_opts = keys %$confdesc_cloudinit;
4987 foreach my $opt (keys %{$conf->{pending}}) {
4988 next if !grep { $_ eq $opt } @cloudinit_opts;
4989 $conf->{$opt} = delete $conf->{pending}->{$opt};
4990 }
4991
4992 my $new_conf = { %$conf };
4993 $new_conf->{$key} = $value;
4994 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4995 };
4996
3d7389fe 4997 foreach my $opt (keys %{$conf->{pending}}) {
3a11fadb 4998 next if $selection && !$selection->{$opt};
3d7389fe 4999 my $value = $conf->{pending}->{$opt};
3a11fadb 5000 eval {
51a6f637
AD
5001 if ($opt eq 'hotplug') {
5002 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
5003 } elsif ($opt eq 'tablet') {
b3c2bdd1 5004 die "skip\n" if !$hotplug_features->{usb};
3a11fadb 5005 if ($value == 1) {
d559309f
WB
5006 vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $machine_type);
5007 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $machine_type)
5008 if $arch eq 'aarch64';
3a11fadb 5009 } elsif ($value == 0) {
d559309f
WB
5010 vm_deviceunplug($vmid, $conf, 'tablet');
5011 vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'aarch64';
3a11fadb 5012 }
4eb68604 5013 } elsif ($opt =~ m/^usb\d+$/) {
f745762b
DC
5014 die "skip\n";
5015 # since we cannot reliably hot unplug usb devices
5016 # we are disabling it
4eb68604
DC
5017 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
5018 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
5019 die "skip\n" if !$d;
d559309f 5020 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
8edc9c08 5021 } elsif ($opt eq 'vcpus') {
b3c2bdd1 5022 die "skip\n" if !$hotplug_features->{cpu};
3a11fadb
DM
5023 qemu_cpu_hotplug($vmid, $conf, $value);
5024 } elsif ($opt eq 'balloon') {
81d95ae1 5025 # enable/disable balloning device is not hotpluggable
8fe689e7 5026 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
a1b7d579 5027 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
81d95ae1
DM
5028 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
5029
3a11fadb 5030 # allow manual ballooning if shares is set to zero
4cc1efa6 5031 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
9c2f7069
AD
5032 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
5033 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
5034 }
a1b7d579 5035 } elsif ($opt =~ m/^net(\d+)$/) {
3eec5767 5036 # some changes can be done without hotplug
a1b7d579 5037 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
d559309f 5038 $vmid, $opt, $value, $arch, $machine_type);
74479ee9 5039 } elsif (is_valid_drivename($opt)) {
a05cff86 5040 # some changes can be done without hotplug
9ed7a77c
WB
5041 my $drive = parse_drive($opt, $value);
5042 if (drive_is_cloudinit($drive)) {
5043 &$apply_pending_cloudinit($opt, $value);
5044 }
b3c2bdd1 5045 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
d559309f 5046 $vmid, $opt, $value, 1, $arch, $machine_type);
4d3f29ed
AD
5047 } elsif ($opt =~ m/^memory$/) { #dimms
5048 die "skip\n" if !$hotplug_features->{memory};
6779f1ac 5049 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
c8effec3
AD
5050 } elsif ($opt eq 'cpuunits') {
5051 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
58be00f1 5052 } elsif ($opt eq 'cpulimit') {
c6f773b8 5053 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
58be00f1 5054 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
3a11fadb 5055 } else {
e56beeda 5056 die "skip\n"; # skip non-hot-pluggable options
3d7389fe 5057 }
3a11fadb
DM
5058 };
5059 if (my $err = $@) {
e56beeda
DM
5060 &$add_error($opt, $err) if $err ne "skip\n";
5061 } else {
3a11fadb
DM
5062 # save new config if hotplug was successful
5063 $conf->{$opt} = $value;
5064 delete $conf->{pending}->{$opt};
ffda963f
FG
5065 PVE::QemuConfig->write_config($vmid, $conf);
5066 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
3d7389fe 5067 }
3d7389fe 5068 }
c427973b 5069}
055d554d 5070
3dc38fbb
WB
5071sub try_deallocate_drive {
5072 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
5073
5074 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
5075 my $volid = $drive->{file};
5076 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
5077 my $sid = PVE::Storage::parse_volume_id($volid);
5078 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
cee01bcb
WB
5079
5080 # check if the disk is really unused
cee01bcb 5081 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
77019edf 5082 if is_volume_in_use($storecfg, $conf, $key, $volid);
cee01bcb 5083 PVE::Storage::vdisk_free($storecfg, $volid);
3dc38fbb 5084 return 1;
40b977f3
WL
5085 } else {
5086 # If vm is not owner of this disk remove from config
5087 return 1;
3dc38fbb
WB
5088 }
5089 }
5090
5091 return undef;
5092}
5093
5094sub vmconfig_delete_or_detach_drive {
5095 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
5096
5097 my $drive = parse_drive($opt, $conf->{$opt});
5098
5099 my $rpcenv = PVE::RPCEnvironment::get();
5100 my $authuser = $rpcenv->get_user();
5101
5102 if ($force) {
5103 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
5104 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
5105 } else {
5106 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
5107 }
5108}
5109
055d554d 5110sub vmconfig_apply_pending {
3a11fadb 5111 my ($vmid, $conf, $storecfg) = @_;
c427973b
DM
5112
5113 # cold plug
055d554d 5114
3dc38fbb
WB
5115 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
5116 while (my ($opt, $force) = each %$pending_delete_hash) {
055d554d 5117 die "internal error" if $opt =~ m/^unused/;
ffda963f 5118 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
055d554d
DM
5119 if (!defined($conf->{$opt})) {
5120 vmconfig_undelete_pending_option($conf, $opt);
ffda963f 5121 PVE::QemuConfig->write_config($vmid, $conf);
74479ee9 5122 } elsif (is_valid_drivename($opt)) {
3dc38fbb 5123 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
055d554d
DM
5124 vmconfig_undelete_pending_option($conf, $opt);
5125 delete $conf->{$opt};
ffda963f 5126 PVE::QemuConfig->write_config($vmid, $conf);
055d554d
DM
5127 } else {
5128 vmconfig_undelete_pending_option($conf, $opt);
5129 delete $conf->{$opt};
ffda963f 5130 PVE::QemuConfig->write_config($vmid, $conf);
055d554d
DM
5131 }
5132 }
5133
ffda963f 5134 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
055d554d
DM
5135
5136 foreach my $opt (keys %{$conf->{pending}}) { # add/change
ffda963f 5137 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
055d554d
DM
5138
5139 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
5140 # skip if nothing changed
74479ee9 5141 } elsif (is_valid_drivename($opt)) {
055d554d
DM
5142 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
5143 if defined($conf->{$opt});
5144 $conf->{$opt} = $conf->{pending}->{$opt};
5145 } else {
5146 $conf->{$opt} = $conf->{pending}->{$opt};
5147 }
5148
5149 delete $conf->{pending}->{$opt};
ffda963f 5150 PVE::QemuConfig->write_config($vmid, $conf);
055d554d
DM
5151 }
5152}
5153
3eec5767
DM
5154my $safe_num_ne = sub {
5155 my ($a, $b) = @_;
5156
5157 return 0 if !defined($a) && !defined($b);
5158 return 1 if !defined($a);
5159 return 1 if !defined($b);
5160
5161 return $a != $b;
5162};
5163
5164my $safe_string_ne = sub {
5165 my ($a, $b) = @_;
5166
5167 return 0 if !defined($a) && !defined($b);
5168 return 1 if !defined($a);
5169 return 1 if !defined($b);
5170
5171 return $a ne $b;
5172};
5173
5174sub vmconfig_update_net {
d559309f 5175 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
3eec5767
DM
5176
5177 my $newnet = parse_net($value);
5178
5179 if ($conf->{$opt}) {
5180 my $oldnet = parse_net($conf->{$opt});
5181
5182 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
5183 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
5184 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
5185 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
5186
5187 # for non online change, we try to hot-unplug
7196b757 5188 die "skip\n" if !$hotplug;
3eec5767
DM
5189 vm_deviceunplug($vmid, $conf, $opt);
5190 } else {
5191
5192 die "internal error" if $opt !~ m/net(\d+)/;
5193 my $iface = "tap${vmid}i$1";
a1b7d579 5194
25088687
DM
5195 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
5196 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
16d08ecf 5197 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
25088687 5198 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
3eec5767 5199 PVE::Network::tap_unplug($iface);
4f4fbeb0
WB
5200 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
5201 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
5202 # Rate can be applied on its own but any change above needs to
5203 # include the rate in tap_plug since OVS resets everything.
5204 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
3eec5767 5205 }
38c590d9 5206
25088687
DM
5207 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
5208 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
5209 }
5210
38c590d9 5211 return 1;
3eec5767
DM
5212 }
5213 }
a1b7d579 5214
7196b757 5215 if ($hotplug) {
d559309f 5216 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
38c590d9
DM
5217 } else {
5218 die "skip\n";
5219 }
3eec5767
DM
5220}
5221
a05cff86 5222sub vmconfig_update_disk {
d559309f 5223 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
a05cff86
DM
5224
5225 # fixme: do we need force?
5226
5227 my $drive = parse_drive($opt, $value);
5228
5229 if ($conf->{$opt}) {
5230
5231 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
5232
5233 my $media = $drive->{media} || 'disk';
5234 my $oldmedia = $old_drive->{media} || 'disk';
5235 die "unable to change media type\n" if $media ne $oldmedia;
5236
5237 if (!drive_is_cdrom($old_drive)) {
5238
a1b7d579 5239 if ($drive->{file} ne $old_drive->{file}) {
a05cff86 5240
7196b757 5241 die "skip\n" if !$hotplug;
a05cff86
DM
5242
5243 # unplug and register as unused
5244 vm_deviceunplug($vmid, $conf, $opt);
5245 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
a1b7d579 5246
a05cff86
DM
5247 } else {
5248 # update existing disk
5249
5250 # skip non hotpluggable value
6ecfbb44 5251 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
22de899a 5252 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
6e11f143 5253 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
a05cff86
DM
5254 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
5255 die "skip\n";
5256 }
5257
5258 # apply throttle
5259 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
5260 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
5261 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
5262 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
5263 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
5264 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
5265 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
5266 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
5267 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
5268 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
5269 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
9196a8ec
WB
5270 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
5271 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
5272 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
5273 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
5274 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
5275 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
5276 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
a1b7d579 5277
a05cff86
DM
5278 qemu_block_set_io_throttle($vmid,"drive-$opt",
5279 ($drive->{mbps} || 0)*1024*1024,
5280 ($drive->{mbps_rd} || 0)*1024*1024,
5281 ($drive->{mbps_wr} || 0)*1024*1024,
5282 $drive->{iops} || 0,
5283 $drive->{iops_rd} || 0,
5284 $drive->{iops_wr} || 0,
5285 ($drive->{mbps_max} || 0)*1024*1024,
5286 ($drive->{mbps_rd_max} || 0)*1024*1024,
5287 ($drive->{mbps_wr_max} || 0)*1024*1024,
5288 $drive->{iops_max} || 0,
5289 $drive->{iops_rd_max} || 0,
9196a8ec
WB
5290 $drive->{iops_wr_max} || 0,
5291 $drive->{bps_max_length} || 1,
5292 $drive->{bps_rd_max_length} || 1,
5293 $drive->{bps_wr_max_length} || 1,
5294 $drive->{iops_max_length} || 1,
5295 $drive->{iops_rd_max_length} || 1,
5296 $drive->{iops_wr_max_length} || 1);
a05cff86
DM
5297
5298 }
a1b7d579 5299
a05cff86
DM
5300 return 1;
5301 }
4de1bb25
DM
5302
5303 } else { # cdrom
a1b7d579 5304
4de1bb25
DM
5305 if ($drive->{file} eq 'none') {
5306 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
2d9ddec5
WB
5307 if (drive_is_cloudinit($old_drive)) {
5308 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5309 }
4de1bb25
DM
5310 } else {
5311 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5312 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5313 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5314 }
a1b7d579 5315
34758d66 5316 return 1;
a05cff86
DM
5317 }
5318 }
5319 }
5320
a1b7d579 5321 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4de1bb25 5322 # hotplug new disks
f7b4356f 5323 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
d559309f 5324 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
a05cff86
DM
5325}
5326
1e3baf05 5327sub vm_start {
ba9e1000 5328 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
2189246c 5329 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
1e3baf05 5330
ffda963f
FG
5331 PVE::QemuConfig->lock_config($vmid, sub {
5332 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
1e3baf05 5333
ffda963f 5334 die "you can't start a vm if it's a template\n" if PVE::QemuConfig->is_template($conf);
3dcb98d5 5335
7ceade4c
DC
5336 my $is_suspended = PVE::QemuConfig->has_lock($conf, 'suspended');
5337
5338 PVE::QemuConfig->check_lock($conf)
5339 if !($skiplock || $is_suspended);
1e3baf05 5340
7e8dcf2c 5341 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
1e3baf05 5342
055d554d 5343 if (!$statefile && scalar(keys %{$conf->{pending}})) {
3a11fadb 5344 vmconfig_apply_pending($vmid, $conf, $storecfg);
ffda963f 5345 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
055d554d
DM
5346 }
5347
0c9a7596
AD
5348 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5349
6c47d546
DM
5350 my $defaults = load_defaults();
5351
5352 # set environment variable useful inside network script
5353 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5354
2189246c
AD
5355 my $local_volumes = {};
5356
3b4cf0f0 5357 if ($targetstorage) {
2189246c
AD
5358 foreach_drive($conf, sub {
5359 my ($ds, $drive) = @_;
5360
5361 return if drive_is_cdrom($drive);
5362
5363 my $volid = $drive->{file};
5364
5365 return if !$volid;
5366
5367 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5368
5369 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5370 return if $scfg->{shared};
5371 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5372 });
5373
5374 my $format = undef;
5375
5376 foreach my $opt (sort keys %$local_volumes) {
5377
5378 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5379 my $drive = parse_drive($opt, $conf->{$opt});
5380
5381 #if remote storage is specified, use default format
5382 if ($targetstorage && $targetstorage ne "1") {
5383 $storeid = $targetstorage;
5384 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5385 $format = $defFormat;
5386 } else {
5387 #else we use same format than original
5388 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5389 $format = qemu_img_format($scfg, $volid);
5390 }
5391
5392 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5393 my $newdrive = $drive;
5394 $newdrive->{format} = $format;
5395 $newdrive->{file} = $newvolid;
5396 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5397 $local_volumes->{$opt} = $drivestr;
5398 #pass drive to conf for command line
5399 $conf->{$opt} = $drivestr;
5400 }
5401 }
5402
9e784b11
DC
5403 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-start', 1);
5404
7ceade4c
DC
5405 if ($is_suspended) {
5406 # enforce machine type on suspended vm to ensure HW compatibility
5407 $forcemachine = $conf->{runningmachine};
b0a9a385 5408 print "Resuming suspended VM\n";
7ceade4c
DC
5409 }
5410
67812f9c 5411 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
6c47d546 5412
1e3baf05 5413 my $migrate_port = 0;
5bc1e039 5414 my $migrate_uri;
1e3baf05
DM
5415 if ($statefile) {
5416 if ($statefile eq 'tcp') {
5bc1e039
SP
5417 my $localip = "localhost";
5418 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
af0eba7e 5419 my $nodename = PVE::INotify::nodename();
2de2d6f7 5420
b7a5a225
TL
5421 if (!defined($migration_type)) {
5422 if (defined($datacenterconf->{migration}->{type})) {
5423 $migration_type = $datacenterconf->{migration}->{type};
5424 } else {
5425 $migration_type = 'secure';
5426 }
5427 }
5428
2de2d6f7
TL
5429 if ($migration_type eq 'insecure') {
5430 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5431 if ($migrate_network_addr) {
5432 $localip = $migrate_network_addr;
5433 } else {
5bc1e039 5434 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
2de2d6f7
TL
5435 }
5436
5437 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5bc1e039 5438 }
2de2d6f7 5439
af0eba7e
WB
5440 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5441 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
407e0b8b 5442 $migrate_uri = "tcp:${localip}:${migrate_port}";
6c47d546
DM
5443 push @$cmd, '-incoming', $migrate_uri;
5444 push @$cmd, '-S';
1c9d54bf
TL
5445
5446 } elsif ($statefile eq 'unix') {
5447 # should be default for secure migrations as a ssh TCP forward
5448 # tunnel is not deterministic reliable ready and fails regurarly
5449 # to set up in time, so use UNIX socket forwards
54323eed
TL
5450 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5451 unlink $socket_addr;
5452
5453 $migrate_uri = "unix:$socket_addr";
1c9d54bf
TL
5454
5455 push @$cmd, '-incoming', $migrate_uri;
5456 push @$cmd, '-S';
5457
1e3baf05 5458 } else {
6c47d546 5459 push @$cmd, '-loadstate', $statefile;
1e3baf05 5460 }
91bd6c90
DM
5461 } elsif ($paused) {
5462 push @$cmd, '-S';
1e3baf05
DM
5463 }
5464
1e3baf05 5465 # host pci devices
040b06b7
DA
5466 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5467 my $d = parse_hostpci($conf->{"hostpci$i"});
5468 next if !$d;
b1f72af6
AD
5469 my $pcidevices = $d->{pciid};
5470 foreach my $pcidevice (@$pcidevices) {
2fd24788 5471 my $pciid = $pcidevice->{id};
000fc0a2 5472
b71351a7
DC
5473 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5474 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
b1f72af6 5475 die "no pci device info for device '$pciid'\n" if !$info;
6ab45bd7
DC
5476
5477 if ($d->{mdev}) {
5478 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5479 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5480 } else {
5481 die "can't unbind/bind pci group to vfio '$pciid'\n"
5482 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5483 die "can't reset pci device '$pciid'\n"
5484 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5485 }
b1f72af6 5486 }
040b06b7 5487 }
1e3baf05
DM
5488
5489 PVE::Storage::activate_volumes($storecfg, $vollist);
5490
4f8cfa19
WB
5491 eval {
5492 run_command(['/bin/systemctl', 'stop', "$vmid.scope"],
5493 outfunc => sub {}, errfunc => sub {});
5494 };
5495 # Issues with the above 'stop' not being fully completed are extremely rare, a very low
5496 # timeout should be more than enough here...
5497 PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
2b401189 5498
8e59d952
WB
5499 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5500 : $defaults->{cpuunits};
5501
ccb2e2ea 5502 my $start_timeout = ($conf->{hugepages} || $is_suspended) ? 300 : 30;
f38de678 5503 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
7023f3ea
AD
5504
5505 my %properties = (
5506 Slice => 'qemu.slice',
5507 KillMode => 'none',
5508 CPUShares => $cpuunits
5509 );
5510
5511 if (my $cpulimit = $conf->{cpulimit}) {
5512 $properties{CPUQuota} = int($cpulimit * 100);
5513 }
5514 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5515
503308ed
WB
5516 my $run_qemu = sub {
5517 PVE::Tools::run_fork sub {
d04d6af1 5518 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
503308ed
WB
5519 run_command($cmd, %run_params);
5520 };
5521 };
5522
7023f3ea
AD
5523 if ($conf->{hugepages}) {
5524
5525 my $code = sub {
5526 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5527 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5528
5529 PVE::QemuServer::Memory::hugepages_mount();
5530 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5531
503308ed 5532 eval { $run_qemu->() };
7023f3ea
AD
5533 if (my $err = $@) {
5534 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5535 die $err;
5536 }
5537
5538 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5539 };
5540 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5541
5542 } else {
503308ed 5543 eval { $run_qemu->() };
7023f3ea 5544 }
77cde36b
DC
5545
5546 if (my $err = $@) {
5547 # deactivate volumes if start fails
5548 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5549 die "start failed: $err";
5550 }
1e3baf05 5551
5bc1e039 5552 print "migration listens on $migrate_uri\n" if $migrate_uri;
afdb31d5 5553
b37ecfe6 5554 if ($statefile && $statefile ne 'tcp' && $statefile ne 'unix') {
95381ce0 5555 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
8c609afd 5556 warn $@ if $@;
62de2cbd
DM
5557 }
5558
2189246c
AD
5559 #start nbd server for storage migration
5560 if ($targetstorage) {
2189246c
AD
5561 my $nodename = PVE::INotify::nodename();
5562 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5563 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5564 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5565 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5566
5567 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet', data => { host => "${localip}", port => "${migrate_port}" } } );
5568
5569 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5570
5571 foreach my $opt (sort keys %$local_volumes) {
5572 my $volid = $local_volumes->{$opt};
5573 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5574 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5575 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5576 }
5577 }
5578
1d794448 5579 if ($migratedfrom) {
a89fded1 5580 eval {
8e90138a 5581 set_migration_caps($vmid);
a89fded1 5582 };
1d794448 5583 warn $@ if $@;
a89fded1 5584
1d794448
DM
5585 if ($spice_port) {
5586 print "spice listens on port $spice_port\n";
5587 if ($spice_ticket) {
8e90138a
DM
5588 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice', password => $spice_ticket);
5589 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice', time => "+30");
95a4b4a9
AD
5590 }
5591 }
5592
1d794448 5593 } else {
51153f86
DC
5594 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5595 if !$statefile && $conf->{balloon};
25088687
DM
5596
5597 foreach my $opt (keys %$conf) {
5598 next if $opt !~ m/^net\d+$/;
5599 my $nicconf = parse_net($conf->{$opt});
5600 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5601 }
e18b0b99 5602 }
a1b7d579 5603
eb065317
AD
5604 vm_mon_cmd_nocheck($vmid, 'qom-set',
5605 path => "machine/peripheral/balloon0",
5606 property => "guest-stats-polling-interval",
5607 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5608
7ceade4c 5609 if ($is_suspended && (my $vmstate = $conf->{vmstate})) {
b0a9a385 5610 print "Resumed VM, removing state\n";
7ceade4c
DC
5611 delete $conf->@{qw(lock vmstate runningmachine)};
5612 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5613 PVE::Storage::vdisk_free($storecfg, $vmstate);
5614 PVE::QemuConfig->write_config($vmid, $conf);
5615 }
5616
9e784b11 5617 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'post-start');
1e3baf05
DM
5618 });
5619}
5620
0eedc444
AD
5621sub vm_mon_cmd {
5622 my ($vmid, $execute, %params) = @_;
5623
26f11676
DM
5624 my $cmd = { execute => $execute, arguments => \%params };
5625 vm_qmp_command($vmid, $cmd);
0eedc444
AD
5626}
5627
5628sub vm_mon_cmd_nocheck {
5629 my ($vmid, $execute, %params) = @_;
5630
26f11676
DM
5631 my $cmd = { execute => $execute, arguments => \%params };
5632 vm_qmp_command($vmid, $cmd, 1);
0eedc444
AD
5633}
5634
c971c4f2 5635sub vm_qmp_command {
c5a07de5 5636 my ($vmid, $cmd, $nocheck) = @_;
97d62eb7 5637
c971c4f2 5638 my $res;
26f11676 5639
14db5366 5640 my $timeout;
1688362d
SR
5641 if ($cmd->{arguments}) {
5642 $timeout = delete $cmd->{arguments}->{timeout};
14db5366 5643 }
be190583 5644
c971c4f2
AD
5645 eval {
5646 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
7a6c2150
DM
5647 my $sname = qmp_socket($vmid);
5648 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
c5a07de5 5649 my $qmpclient = PVE::QMPClient->new();
dab36e1e 5650
14db5366 5651 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
dab36e1e
DM
5652 } else {
5653 die "unable to open monitor socket\n";
5654 }
c971c4f2 5655 };
26f11676 5656 if (my $err = $@) {
c971c4f2
AD
5657 syslog("err", "VM $vmid qmp command failed - $err");
5658 die $err;
5659 }
5660
5661 return $res;
5662}
5663
9df5cbcc
DM
5664sub vm_human_monitor_command {
5665 my ($vmid, $cmdline) = @_;
5666
f5eb281a 5667 my $cmd = {
9df5cbcc
DM
5668 execute => 'human-monitor-command',
5669 arguments => { 'command-line' => $cmdline},
5670 };
5671
5672 return vm_qmp_command($vmid, $cmd);
5673}
5674
1e3baf05 5675sub vm_commandline {
b14477e7 5676 my ($storecfg, $vmid, $snapname) = @_;
1e3baf05 5677
ffda963f 5678 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5679
b14477e7
RV
5680 if ($snapname) {
5681 my $snapshot = $conf->{snapshots}->{$snapname};
87d92707
TL
5682 die "snapshot '$snapname' does not exist\n" if !defined($snapshot);
5683
5684 $snapshot->{digest} = $conf->{digest}; # keep file digest for API
b14477e7 5685
b14477e7
RV
5686 $conf = $snapshot;
5687 }
5688
1e3baf05
DM
5689 my $defaults = load_defaults();
5690
6b64503e 5691 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
1e3baf05 5692
5930c1ff 5693 return PVE::Tools::cmd2string($cmd);
1e3baf05
DM
5694}
5695
5696sub vm_reset {
5697 my ($vmid, $skiplock) = @_;
5698
ffda963f 5699 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5700
ffda963f 5701 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5702
ffda963f 5703 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 5704
816e2c4a 5705 vm_mon_cmd($vmid, "system_reset");
ff1a2432
DM
5706 });
5707}
5708
5709sub get_vm_volumes {
5710 my ($conf) = @_;
1e3baf05 5711
ff1a2432 5712 my $vollist = [];
d5769dc2 5713 foreach_volid($conf, sub {
392f8b5d 5714 my ($volid, $attr) = @_;
ff1a2432 5715
d5769dc2 5716 return if $volid =~ m|^/|;
ff1a2432 5717
d5769dc2
DM
5718 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5719 return if !$sid;
ff1a2432
DM
5720
5721 push @$vollist, $volid;
1e3baf05 5722 });
ff1a2432
DM
5723
5724 return $vollist;
5725}
5726
5727sub vm_stop_cleanup {
70b04821 5728 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
ff1a2432 5729
745fed70 5730 eval {
ff1a2432 5731
254575e9
DM
5732 if (!$keepActive) {
5733 my $vollist = get_vm_volumes($conf);
5734 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5735 }
a1b7d579 5736
ab6a046f 5737 foreach my $ext (qw(mon qmp pid vnc qga)) {
961bfcb2
DM
5738 unlink "/var/run/qemu-server/${vmid}.$ext";
5739 }
a1b7d579 5740
6dbcb073
DC
5741 if ($conf->{ivshmem}) {
5742 my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
4c5a6a24
TL
5743 # just delete it for now, VMs which have this already open do not
5744 # are affected, but new VMs will get a separated one. If this
5745 # becomes an issue we either add some sort of ref-counting or just
5746 # add a "don't delete on stop" flag to the ivshmem format.
6dbcb073
DC
5747 unlink '/dev/shm/pve-shm-' . ($ivshmem->{name} // $vmid);
5748 }
5749
6ab45bd7
DC
5750 foreach my $key (keys %$conf) {
5751 next if $key !~ m/^hostpci(\d+)$/;
5752 my $hostpciindex = $1;
5753 my $d = parse_hostpci($conf->{$key});
5754 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $hostpciindex);
5755
5756 foreach my $pci (@{$d->{pciid}}) {
2fd24788 5757 my $pciid = $pci->{id};
6ab45bd7
DC
5758 PVE::SysFSTools::pci_cleanup_mdev_device($pciid, $uuid);
5759 }
5760 }
5761
70b04821 5762 vmconfig_apply_pending($vmid, $conf, $storecfg) if $apply_pending_changes;
745fed70
DM
5763 };
5764 warn $@ if $@; # avoid errors - just warn
1e3baf05
DM
5765}
5766
e6c3b671 5767# Note: use $nockeck to skip tests if VM configuration file exists.
254575e9
DM
5768# We need that when migration VMs to other nodes (files already moved)
5769# Note: we set $keepActive in vzdump stop mode - volumes need to stay active
1e3baf05 5770sub vm_stop {
af30308f 5771 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
9269013a 5772
9269013a 5773 $force = 1 if !defined($force) && !$shutdown;
1e3baf05 5774
af30308f
DM
5775 if ($migratedfrom){
5776 my $pid = check_running($vmid, $nocheck, $migratedfrom);
5777 kill 15, $pid if $pid;
ffda963f 5778 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
70b04821 5779 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 0);
af30308f
DM
5780 return;
5781 }
5782
ffda963f 5783 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5784
e6c3b671 5785 my $pid = check_running($vmid, $nocheck);
ff1a2432 5786 return if !$pid;
1e3baf05 5787
ff1a2432 5788 my $conf;
e6c3b671 5789 if (!$nocheck) {
ffda963f
FG
5790 $conf = PVE::QemuConfig->load_config($vmid);
5791 PVE::QemuConfig->check_lock($conf) if !$skiplock;
7f4a5b5a 5792 if (!defined($timeout) && $shutdown && $conf->{startup}) {
38f7f26c 5793 my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
7f4a5b5a
DM
5794 $timeout = $opts->{down} if $opts->{down};
5795 }
9e784b11 5796 PVE::GuestHelpers::exec_hookscript($conf, $vmid, 'pre-stop');
e6c3b671 5797 }
19672434 5798
9269013a
DM
5799 eval {
5800 if ($shutdown) {
9d66b397 5801 if (defined($conf) && parse_guest_agent($conf)->{enabled}) {
0eb21691
SR
5802 vm_qmp_command($vmid, {
5803 execute => "guest-shutdown",
5804 arguments => { timeout => $timeout }
5805 }, $nocheck);
1c0c1c17 5806 } else {
2ea54503 5807 vm_qmp_command($vmid, { execute => "system_powerdown" }, $nocheck);
1c0c1c17 5808 }
9269013a 5809 } else {
2ea54503 5810 vm_qmp_command($vmid, { execute => "quit" }, $nocheck);
afdb31d5 5811 }
9269013a 5812 };
1e3baf05
DM
5813 my $err = $@;
5814
5815 if (!$err) {
0eb21691
SR
5816 $timeout = 60 if !defined($timeout);
5817
1e3baf05 5818 my $count = 0;
e6c3b671 5819 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
5820 $count++;
5821 sleep 1;
5822 }
5823
5824 if ($count >= $timeout) {
9269013a
DM
5825 if ($force) {
5826 warn "VM still running - terminating now with SIGTERM\n";
5827 kill 15, $pid;
5828 } else {
5829 die "VM quit/powerdown failed - got timeout\n";
5830 }
5831 } else {
70b04821 5832 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
9269013a 5833 return;
1e3baf05
DM
5834 }
5835 } else {
9269013a
DM
5836 if ($force) {
5837 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5838 kill 15, $pid;
5839 } else {
afdb31d5 5840 die "VM quit/powerdown failed\n";
9269013a 5841 }
1e3baf05
DM
5842 }
5843
5844 # wait again
ff1a2432 5845 $timeout = 10;
1e3baf05
DM
5846
5847 my $count = 0;
e6c3b671 5848 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
5849 $count++;
5850 sleep 1;
5851 }
5852
5853 if ($count >= $timeout) {
ff1a2432 5854 warn "VM still running - terminating now with SIGKILL\n";
1e3baf05 5855 kill 9, $pid;
ff1a2432 5856 sleep 1;
1e3baf05
DM
5857 }
5858
70b04821 5859 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
ff1a2432 5860 });
1e3baf05
DM
5861}
5862
5863sub vm_suspend {
48b4cdc2 5864 my ($vmid, $skiplock, $includestate, $statestorage) = @_;
159719e5
DC
5865
5866 my $conf;
5867 my $path;
5868 my $storecfg;
5869 my $vmstate;
1e3baf05 5870
ffda963f 5871 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5872
159719e5 5873 $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5874
159719e5 5875 my $is_backing_up = PVE::QemuConfig->has_lock($conf, 'backup');
e79706d4 5876 PVE::QemuConfig->check_lock($conf)
159719e5
DC
5877 if !($skiplock || $is_backing_up);
5878
5879 die "cannot suspend to disk during backup\n"
5880 if $is_backing_up && $includestate;
bcb7c9cf 5881
159719e5
DC
5882 if ($includestate) {
5883 $conf->{lock} = 'suspending';
5884 my $date = strftime("%Y-%m-%d", localtime(time()));
5885 $storecfg = PVE::Storage::config();
48b4cdc2 5886 $vmstate = PVE::QemuConfig->__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
159719e5
DC
5887 $path = PVE::Storage::path($storecfg, $vmstate);
5888 PVE::QemuConfig->write_config($vmid, $conf);
5889 } else {
5890 vm_mon_cmd($vmid, "stop");
5891 }
1e3baf05 5892 });
159719e5
DC
5893
5894 if ($includestate) {
5895 # save vm state
5896 PVE::Storage::activate_volumes($storecfg, [$vmstate]);
5897
5898 eval {
5899 vm_mon_cmd($vmid, "savevm-start", statefile => $path);
5900 for(;;) {
5901 my $state = vm_mon_cmd_nocheck($vmid, "query-savevm");
5902 if (!$state->{status}) {
5903 die "savevm not active\n";
5904 } elsif ($state->{status} eq 'active') {
5905 sleep(1);
5906 next;
5907 } elsif ($state->{status} eq 'completed') {
b0a9a385 5908 print "State saved, quitting\n";
159719e5
DC
5909 last;
5910 } elsif ($state->{status} eq 'failed' && $state->{error}) {
5911 die "query-savevm failed with error '$state->{error}'\n"
5912 } else {
5913 die "query-savevm returned status '$state->{status}'\n";
5914 }
5915 }
5916 };
5917 my $err = $@;
5918
5919 PVE::QemuConfig->lock_config($vmid, sub {
5920 $conf = PVE::QemuConfig->load_config($vmid);
5921 if ($err) {
5922 # cleanup, but leave suspending lock, to indicate something went wrong
5923 eval {
5924 vm_mon_cmd($vmid, "savevm-end");
5925 PVE::Storage::deactivate_volumes($storecfg, [$vmstate]);
5926 PVE::Storage::vdisk_free($storecfg, $vmstate);
5927 delete $conf->@{qw(vmstate runningmachine)};
5928 PVE::QemuConfig->write_config($vmid, $conf);
5929 };
5930 warn $@ if $@;
5931 die $err;
5932 }
5933
5934 die "lock changed unexpectedly\n"
5935 if !PVE::QemuConfig->has_lock($conf, 'suspending');
5936
5937 vm_qmp_command($vmid, { execute => "quit" });
5938 $conf->{lock} = 'suspended';
5939 PVE::QemuConfig->write_config($vmid, $conf);
5940 });
5941 }
1e3baf05
DM
5942}
5943
5944sub vm_resume {
289e0b85 5945 my ($vmid, $skiplock, $nocheck) = @_;
1e3baf05 5946
ffda963f 5947 PVE::QemuConfig->lock_config($vmid, sub {
3e24733b
FG
5948 my $vm_mon_cmd = $nocheck ? \&vm_mon_cmd_nocheck : \&vm_mon_cmd;
5949 my $res = $vm_mon_cmd->($vmid, 'query-status');
c2786bed
DC
5950 my $resume_cmd = 'cont';
5951
5952 if ($res->{status} && $res->{status} eq 'suspended') {
5953 $resume_cmd = 'system_wakeup';
5954 }
5955
289e0b85 5956 if (!$nocheck) {
1e3baf05 5957
ffda963f 5958 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5959
e79706d4
FG
5960 PVE::QemuConfig->check_lock($conf)
5961 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
289e0b85 5962 }
3e24733b
FG
5963
5964 $vm_mon_cmd->($vmid, $resume_cmd);
1e3baf05
DM
5965 });
5966}
5967
5fdbe4f0
DM
5968sub vm_sendkey {
5969 my ($vmid, $skiplock, $key) = @_;
1e3baf05 5970
ffda963f 5971 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5972
ffda963f 5973 my $conf = PVE::QemuConfig->load_config($vmid);
f5eb281a 5974
7b7c6d1b 5975 # there is no qmp command, so we use the human monitor command
d30820d6
DC
5976 my $res = vm_human_monitor_command($vmid, "sendkey $key");
5977 die $res if $res ne '';
1e3baf05
DM
5978 });
5979}
5980
5981sub vm_destroy {
5982 my ($storecfg, $vmid, $skiplock) = @_;
5983
ffda963f 5984 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5985
ffda963f 5986 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5987
ff1a2432 5988 if (!check_running($vmid)) {
15cc8784 5989 destroy_vm($storecfg, $vmid, undef, $skiplock);
ff1a2432
DM
5990 } else {
5991 die "VM $vmid is running - destroy failed\n";
1e3baf05
DM
5992 }
5993 });
5994}
5995
3e16d5fc
DM
5996# vzdump restore implementaion
5997
ed221350 5998sub tar_archive_read_firstfile {
3e16d5fc 5999 my $archive = shift;
afdb31d5 6000
3e16d5fc
DM
6001 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
6002
6003 # try to detect archive type first
387ba257 6004 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
3e16d5fc 6005 die "unable to open file '$archive'\n";
387ba257 6006 my $firstfile = <$fh>;
3e16d5fc 6007 kill 15, $pid;
387ba257 6008 close $fh;
3e16d5fc
DM
6009
6010 die "ERROR: archive contaions no data\n" if !$firstfile;
6011 chomp $firstfile;
6012
6013 return $firstfile;
6014}
6015
ed221350
DM
6016sub tar_restore_cleanup {
6017 my ($storecfg, $statfile) = @_;
3e16d5fc
DM
6018
6019 print STDERR "starting cleanup\n";
6020
6021 if (my $fd = IO::File->new($statfile, "r")) {
6022 while (defined(my $line = <$fd>)) {
6023 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6024 my $volid = $2;
6025 eval {
6026 if ($volid =~ m|^/|) {
6027 unlink $volid || die 'unlink failed\n';
6028 } else {
ed221350 6029 PVE::Storage::vdisk_free($storecfg, $volid);
3e16d5fc 6030 }
afdb31d5 6031 print STDERR "temporary volume '$volid' sucessfuly removed\n";
3e16d5fc
DM
6032 };
6033 print STDERR "unable to cleanup '$volid' - $@" if $@;
6034 } else {
6035 print STDERR "unable to parse line in statfile - $line";
afdb31d5 6036 }
3e16d5fc
DM
6037 }
6038 $fd->close();
6039 }
6040}
6041
6042sub restore_archive {
a0d1b1a2 6043 my ($archive, $vmid, $user, $opts) = @_;
3e16d5fc 6044
91bd6c90
DM
6045 my $format = $opts->{format};
6046 my $comp;
6047
6048 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
6049 $format = 'tar' if !$format;
6050 $comp = 'gzip';
6051 } elsif ($archive =~ m/\.tar$/) {
6052 $format = 'tar' if !$format;
6053 } elsif ($archive =~ m/.tar.lzo$/) {
6054 $format = 'tar' if !$format;
6055 $comp = 'lzop';
6056 } elsif ($archive =~ m/\.vma$/) {
6057 $format = 'vma' if !$format;
6058 } elsif ($archive =~ m/\.vma\.gz$/) {
6059 $format = 'vma' if !$format;
6060 $comp = 'gzip';
6061 } elsif ($archive =~ m/\.vma\.lzo$/) {
6062 $format = 'vma' if !$format;
6063 $comp = 'lzop';
6064 } else {
6065 $format = 'vma' if !$format; # default
6066 }
6067
6068 # try to detect archive format
6069 if ($format eq 'tar') {
6070 return restore_tar_archive($archive, $vmid, $user, $opts);
6071 } else {
6072 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
6073 }
6074}
6075
6076sub restore_update_config_line {
6077 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
6078
6079 return if $line =~ m/^\#qmdump\#/;
6080 return if $line =~ m/^\#vzdump\#/;
6081 return if $line =~ m/^lock:/;
6082 return if $line =~ m/^unused\d+:/;
6083 return if $line =~ m/^parent:/;
6084
b5b99790 6085 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
91bd6c90
DM
6086 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
6087 # try to convert old 1.X settings
6088 my ($id, $ind, $ethcfg) = ($1, $2, $3);
6089 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
6090 my ($model, $macaddr) = split(/\=/, $devconfig);
b5b99790 6091 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
91bd6c90
DM
6092 my $net = {
6093 model => $model,
6094 bridge => "vmbr$ind",
6095 macaddr => $macaddr,
6096 };
6097 my $netstr = print_net($net);
6098
6099 print $outfd "net$cookie->{netcount}: $netstr\n";
6100 $cookie->{netcount}++;
6101 }
6102 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
6103 my ($id, $netstr) = ($1, $2);
6104 my $net = parse_net($netstr);
b5b99790 6105 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
91bd6c90
DM
6106 $netstr = print_net($net);
6107 print $outfd "$id: $netstr\n";
6470743f 6108 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
91bd6c90 6109 my $virtdev = $1;
907ea891 6110 my $value = $3;
d9faf790
WB
6111 my $di = parse_drive($virtdev, $value);
6112 if (defined($di->{backup}) && !$di->{backup}) {
91bd6c90 6113 print $outfd "#$line";
c0f7406e 6114 } elsif ($map->{$virtdev}) {
8fd57431 6115 delete $di->{format}; # format can change on restore
91bd6c90 6116 $di->{file} = $map->{$virtdev};
ed221350 6117 $value = print_drive($vmid, $di);
91bd6c90
DM
6118 print $outfd "$virtdev: $value\n";
6119 } else {
6120 print $outfd $line;
6121 }
1a0c2f03 6122 } elsif (($line =~ m/^vmgenid: (.*)/)) {
babecffe 6123 my $vmgenid = $1;
6ee499ff 6124 if ($vmgenid ne '0') {
1a0c2f03 6125 # always generate a new vmgenid if there was a valid one setup
6ee499ff
DC
6126 $vmgenid = generate_uuid();
6127 }
1a0c2f03 6128 print $outfd "vmgenid: $vmgenid\n";
19a5dd55
WL
6129 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
6130 my ($uuid, $uuid_str);
6131 UUID::generate($uuid);
6132 UUID::unparse($uuid, $uuid_str);
6133 my $smbios1 = parse_smbios1($2);
6134 $smbios1->{uuid} = $uuid_str;
6135 print $outfd $1.print_smbios1($smbios1)."\n";
91bd6c90
DM
6136 } else {
6137 print $outfd $line;
6138 }
6139}
6140
6141sub scan_volids {
6142 my ($cfg, $vmid) = @_;
6143
6144 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid);
6145
6146 my $volid_hash = {};
6147 foreach my $storeid (keys %$info) {
6148 foreach my $item (@{$info->{$storeid}}) {
6149 next if !($item->{volid} && $item->{size});
5996a936 6150 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
91bd6c90
DM
6151 $volid_hash->{$item->{volid}} = $item;
6152 }
6153 }
6154
6155 return $volid_hash;
6156}
6157
77019edf
WB
6158sub is_volume_in_use {
6159 my ($storecfg, $conf, $skip_drive, $volid) = @_;
a8e2f942 6160
77019edf 6161 my $path = PVE::Storage::path($storecfg, $volid);
a8e2f942
DM
6162
6163 my $scan_config = sub {
6164 my ($cref, $snapname) = @_;
6165
6166 foreach my $key (keys %$cref) {
6167 my $value = $cref->{$key};
74479ee9 6168 if (is_valid_drivename($key)) {
a8e2f942
DM
6169 next if $skip_drive && $key eq $skip_drive;
6170 my $drive = parse_drive($key, $value);
6171 next if !$drive || !$drive->{file} || drive_is_cdrom($drive);
77019edf 6172 return 1 if $volid eq $drive->{file};
a8e2f942 6173 if ($drive->{file} =~ m!^/!) {
77019edf 6174 return 1 if $drive->{file} eq $path;
a8e2f942
DM
6175 } else {
6176 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file}, 1);
6177 next if !$storeid;
6178 my $scfg = PVE::Storage::storage_config($storecfg, $storeid, 1);
6179 next if !$scfg;
77019edf 6180 return 1 if $path eq PVE::Storage::path($storecfg, $drive->{file}, $snapname);
a8e2f942
DM
6181 }
6182 }
6183 }
77019edf
WB
6184
6185 return 0;
a8e2f942
DM
6186 };
6187
77019edf 6188 return 1 if &$scan_config($conf);
a8e2f942
DM
6189
6190 undef $skip_drive;
6191
77019edf
WB
6192 foreach my $snapname (keys %{$conf->{snapshots}}) {
6193 return 1 if &$scan_config($conf->{snapshots}->{$snapname}, $snapname);
a8e2f942
DM
6194 }
6195
77019edf 6196 return 0;
a8e2f942
DM
6197}
6198
91bd6c90
DM
6199sub update_disksize {
6200 my ($vmid, $conf, $volid_hash) = @_;
be190583 6201
91bd6c90 6202 my $changes;
53b81297 6203 my $prefix = "VM $vmid:";
91bd6c90 6204
c449137a
DC
6205 # used and unused disks
6206 my $referenced = {};
91bd6c90 6207
5996a936
DM
6208 # Note: it is allowed to define multiple storages with same path (alias), so
6209 # we need to check both 'volid' and real 'path' (two different volid can point
6210 # to the same path).
6211
c449137a 6212 my $referencedpath = {};
be190583 6213
91bd6c90
DM
6214 # update size info
6215 foreach my $opt (keys %$conf) {
74479ee9 6216 if (is_valid_drivename($opt)) {
ed221350 6217 my $drive = parse_drive($opt, $conf->{$opt});
91bd6c90
DM
6218 my $volid = $drive->{file};
6219 next if !$volid;
6220
c449137a 6221 $referenced->{$volid} = 1;
be190583 6222 if ($volid_hash->{$volid} &&
5996a936 6223 (my $path = $volid_hash->{$volid}->{path})) {
c449137a 6224 $referencedpath->{$path} = 1;
5996a936 6225 }
91bd6c90 6226
ed221350 6227 next if drive_is_cdrom($drive);
91bd6c90
DM
6228 next if !$volid_hash->{$volid};
6229
6230 $drive->{size} = $volid_hash->{$volid}->{size};
7a907ce6
DM
6231 my $new = print_drive($vmid, $drive);
6232 if ($new ne $conf->{$opt}) {
6233 $changes = 1;
6234 $conf->{$opt} = $new;
53b81297 6235 print "$prefix update disk '$opt' information.\n";
7a907ce6 6236 }
91bd6c90
DM
6237 }
6238 }
6239
5996a936
DM
6240 # remove 'unusedX' entry if volume is used
6241 foreach my $opt (keys %$conf) {
6242 next if $opt !~ m/^unused\d+$/;
6243 my $volid = $conf->{$opt};
6244 my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
c449137a 6245 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
53b81297 6246 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5996a936
DM
6247 $changes = 1;
6248 delete $conf->{$opt};
6249 }
c449137a
DC
6250
6251 $referenced->{$volid} = 1;
6252 $referencedpath->{$path} = 1 if $path;
5996a936
DM
6253 }
6254
91bd6c90
DM
6255 foreach my $volid (sort keys %$volid_hash) {
6256 next if $volid =~ m/vm-$vmid-state-/;
c449137a 6257 next if $referenced->{$volid};
5996a936
DM
6258 my $path = $volid_hash->{$volid}->{path};
6259 next if !$path; # just to be sure
c449137a 6260 next if $referencedpath->{$path};
91bd6c90 6261 $changes = 1;
53b81297
TL
6262 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
6263 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
c449137a 6264 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
91bd6c90
DM
6265 }
6266
6267 return $changes;
6268}
6269
6270sub rescan {
9224dcee 6271 my ($vmid, $nolock, $dryrun) = @_;
91bd6c90 6272
20519efc 6273 my $cfg = PVE::Storage::config();
91bd6c90 6274
b9a1a3ab
TL
6275 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
6276 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
4771526a
AA
6277 foreach my $stor (keys %{$cfg->{ids}}) {
6278 delete($cfg->{ids}->{$stor}) if ! $cfg->{ids}->{$stor}->{content}->{images};
6279 }
6280
53b81297 6281 print "rescan volumes...\n";
91bd6c90
DM
6282 my $volid_hash = scan_volids($cfg, $vmid);
6283
6284 my $updatefn = sub {
6285 my ($vmid) = @_;
6286
ffda963f 6287 my $conf = PVE::QemuConfig->load_config($vmid);
be190583 6288
ffda963f 6289 PVE::QemuConfig->check_lock($conf);
91bd6c90 6290
03da3f0d
DM
6291 my $vm_volids = {};
6292 foreach my $volid (keys %$volid_hash) {
6293 my $info = $volid_hash->{$volid};
6294 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
6295 }
6296
6297 my $changes = update_disksize($vmid, $conf, $vm_volids);
91bd6c90 6298
9224dcee 6299 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
91bd6c90
DM
6300 };
6301
6302 if (defined($vmid)) {
6303 if ($nolock) {
6304 &$updatefn($vmid);
6305 } else {
ffda963f 6306 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
91bd6c90
DM
6307 }
6308 } else {
6309 my $vmlist = config_list();
6310 foreach my $vmid (keys %$vmlist) {
6311 if ($nolock) {
6312 &$updatefn($vmid);
6313 } else {
ffda963f 6314 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
be190583 6315 }
91bd6c90
DM
6316 }
6317 }
6318}
6319
6320sub restore_vma_archive {
6321 my ($archive, $vmid, $user, $opts, $comp) = @_;
6322
91bd6c90
DM
6323 my $readfrom = $archive;
6324
7c536e11
WB
6325 my $cfg = PVE::Storage::config();
6326 my $commands = [];
6327 my $bwlimit = $opts->{bwlimit};
6328
6329 my $dbg_cmdstring = '';
6330 my $add_pipe = sub {
6331 my ($cmd) = @_;
6332 push @$commands, $cmd;
6333 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
6334 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
91bd6c90 6335 $readfrom = '-';
7c536e11
WB
6336 };
6337
6338 my $input = undef;
6339 if ($archive eq '-') {
6340 $input = '<&STDIN';
6341 } else {
6342 # If we use a backup from a PVE defined storage we also consider that
6343 # storage's rate limit:
6344 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
6345 if (defined($volid)) {
6346 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
6347 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
6348 if ($readlimit) {
6349 print STDERR "applying read rate limit: $readlimit\n";
9444c6e4 6350 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7c536e11
WB
6351 $add_pipe->($cstream);
6352 }
6353 }
6354 }
6355
6356 if ($comp) {
6357 my $cmd;
91bd6c90 6358 if ($comp eq 'gzip') {
7c536e11 6359 $cmd = ['zcat', $readfrom];
91bd6c90 6360 } elsif ($comp eq 'lzop') {
7c536e11 6361 $cmd = ['lzop', '-d', '-c', $readfrom];
91bd6c90
DM
6362 } else {
6363 die "unknown compression method '$comp'\n";
6364 }
7c536e11 6365 $add_pipe->($cmd);
91bd6c90
DM
6366 }
6367
6368 my $tmpdir = "/var/tmp/vzdumptmp$$";
6369 rmtree $tmpdir;
6370
6371 # disable interrupts (always do cleanups)
5b97ef24
TL
6372 local $SIG{INT} =
6373 local $SIG{TERM} =
6374 local $SIG{QUIT} =
6375 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
91bd6c90
DM
6376
6377 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
6378 POSIX::mkfifo($mapfifo, 0600);
6379 my $fifofh;
6380
6381 my $openfifo = sub {
6382 open($fifofh, '>', $mapfifo) || die $!;
6383 };
6384
7c536e11 6385 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
91bd6c90
DM
6386
6387 my $oldtimeout;
6388 my $timeout = 5;
6389
6390 my $devinfo = {};
6391
6392 my $rpcenv = PVE::RPCEnvironment::get();
6393
ffda963f 6394 my $conffile = PVE::QemuConfig->config_file($vmid);
91bd6c90
DM
6395 my $tmpfn = "$conffile.$$.tmp";
6396
ed221350 6397 # Note: $oldconf is undef if VM does not exists
ffda963f
FG
6398 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6399 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
ed221350 6400
7c536e11
WB
6401 my %storage_limits;
6402
91bd6c90
DM
6403 my $print_devmap = sub {
6404 my $virtdev_hash = {};
6405
6406 my $cfgfn = "$tmpdir/qemu-server.conf";
6407
6408 # we can read the config - that is already extracted
6409 my $fh = IO::File->new($cfgfn, "r") ||
6410 "unable to read qemu-server.conf - $!\n";
6411
6738ab9c 6412 my $fwcfgfn = "$tmpdir/qemu-server.fw";
3457d090
WL
6413 if (-f $fwcfgfn) {
6414 my $pve_firewall_dir = '/etc/pve/firewall';
6415 mkdir $pve_firewall_dir; # make sure the dir exists
6416 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6417 }
6738ab9c 6418
91bd6c90
DM
6419 while (defined(my $line = <$fh>)) {
6420 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6421 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6422 die "archive does not contain data for drive '$virtdev'\n"
6423 if !$devinfo->{$devname};
6424 if (defined($opts->{storage})) {
6425 $storeid = $opts->{storage} || 'local';
6426 } elsif (!$storeid) {
6427 $storeid = 'local';
6428 }
6429 $format = 'raw' if !$format;
6430 $devinfo->{$devname}->{devname} = $devname;
6431 $devinfo->{$devname}->{virtdev} = $virtdev;
6432 $devinfo->{$devname}->{format} = $format;
6433 $devinfo->{$devname}->{storeid} = $storeid;
6434
be190583 6435 # check permission on storage
91bd6c90
DM
6436 my $pool = $opts->{pool}; # todo: do we need that?
6437 if ($user ne 'root@pam') {
6438 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6439 }
6440
7c536e11
WB
6441 $storage_limits{$storeid} = $bwlimit;
6442
91bd6c90 6443 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
c4ab3c55
ML
6444 } elsif ($line =~ m/^((?:ide|sata|scsi)\d+):\s*(.*)\s*$/) {
6445 my $virtdev = $1;
6446 my $drive = parse_drive($virtdev, $2);
6447 if (drive_is_cloudinit($drive)) {
6448 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
6449 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
6450 my $format = qemu_img_format($scfg, $volname); # has 'raw' fallback
6451
6452 my $d = {
6453 format => $format,
6454 storeid => $opts->{storage} // $storeid,
6455 size => PVE::QemuServer::Cloudinit::CLOUDINIT_DISK_SIZE,
6456 file => $drive->{file}, # to make drive_is_cloudinit check possible
6457 name => "vm-$vmid-cloudinit",
87056e18 6458 is_cloudinit => 1,
c4ab3c55
ML
6459 };
6460 $virtdev_hash->{$virtdev} = $d;
6461 }
91bd6c90
DM
6462 }
6463 }
6464
7c536e11
WB
6465 foreach my $key (keys %storage_limits) {
6466 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$key], $bwlimit);
6467 next if !$limit;
6468 print STDERR "rate limit for storage $key: $limit KiB/s\n";
6469 $storage_limits{$key} = $limit * 1024;
6470 }
6471
91bd6c90 6472 foreach my $devname (keys %$devinfo) {
be190583
DM
6473 die "found no device mapping information for device '$devname'\n"
6474 if !$devinfo->{$devname}->{virtdev};
91bd6c90
DM
6475 }
6476
ed221350 6477 # create empty/temp config
be190583 6478 if ($oldconf) {
ed221350
DM
6479 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
6480 foreach_drive($oldconf, sub {
6481 my ($ds, $drive) = @_;
6482
bf4a933e 6483 return if !$drive->{is_cloudinit} && drive_is_cdrom($drive);
ed221350
DM
6484
6485 my $volid = $drive->{file};
ed221350
DM
6486 return if !$volid || $volid =~ m|^/|;
6487
6488 my ($path, $owner) = PVE::Storage::path($cfg, $volid);
6489 return if !$path || !$owner || ($owner != $vmid);
6490
6491 # Note: only delete disk we want to restore
6492 # other volumes will become unused
6493 if ($virtdev_hash->{$ds}) {
6b72854b
FG
6494 eval { PVE::Storage::vdisk_free($cfg, $volid); };
6495 if (my $err = $@) {
6496 warn $err;
6497 }
ed221350
DM
6498 }
6499 });
381b8fae 6500
2b2923ae 6501 # delete vmstate files, after the restore we have no snapshots anymore
381b8fae
DC
6502 foreach my $snapname (keys %{$oldconf->{snapshots}}) {
6503 my $snap = $oldconf->{snapshots}->{$snapname};
6504 if ($snap->{vmstate}) {
6505 eval { PVE::Storage::vdisk_free($cfg, $snap->{vmstate}); };
6506 if (my $err = $@) {
6507 warn $err;
6508 }
6509 }
6510 }
ed221350
DM
6511 }
6512
6513 my $map = {};
91bd6c90
DM
6514 foreach my $virtdev (sort keys %$virtdev_hash) {
6515 my $d = $virtdev_hash->{$virtdev};
6516 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
7c536e11
WB
6517 my $storeid = $d->{storeid};
6518 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
6519
6520 my $map_opts = '';
6521 if (my $limit = $storage_limits{$storeid}) {
6522 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6523 }
8fd57431
DM
6524
6525 # test if requested format is supported
7c536e11 6526 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($cfg, $storeid);
8fd57431
DM
6527 my $supported = grep { $_ eq $d->{format} } @$validFormats;
6528 $d->{format} = $defFormat if !$supported;
6529
87056e18
TL
6530 my $name;
6531 if ($d->{is_cloudinit}) {
6532 $name = $d->{name};
6533 $name .= ".$d->{format}" if $d->{format} ne 'raw';
c4ab3c55 6534 }
2b2923ae
TL
6535
6536 my $volid = PVE::Storage::vdisk_alloc($cfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
91bd6c90
DM
6537 print STDERR "new volume ID is '$volid'\n";
6538 $d->{volid} = $volid;
91bd6c90 6539
2b2923ae 6540 PVE::Storage::activate_volumes($cfg, [$volid]);
5f96f4df 6541
91bd6c90 6542 my $write_zeros = 1;
88240a83 6543 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
91bd6c90
DM
6544 $write_zeros = 0;
6545 }
6546
87056e18
TL
6547 if (!$d->{is_cloudinit}) {
6548 my $path = PVE::Storage::path($cfg, $volid);
6549
c4ab3c55 6550 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
91bd6c90 6551
c4ab3c55
ML
6552 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6553 }
91bd6c90
DM
6554 $map->{$virtdev} = $volid;
6555 }
6556
6557 $fh->seek(0, 0) || die "seek failed - $!\n";
6558
6559 my $outfd = new IO::File ($tmpfn, "w") ||
6560 die "unable to write config for VM $vmid\n";
6561
6562 my $cookie = { netcount => 0 };
6563 while (defined(my $line = <$fh>)) {
be190583 6564 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
91bd6c90
DM
6565 }
6566
6567 $fh->close();
6568 $outfd->close();
6569 };
6570
6571 eval {
6572 # enable interrupts
6cb0144a
EK
6573 local $SIG{INT} =
6574 local $SIG{TERM} =
6575 local $SIG{QUIT} =
6576 local $SIG{HUP} =
6577 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
91bd6c90
DM
6578 local $SIG{ALRM} = sub { die "got timeout\n"; };
6579
6580 $oldtimeout = alarm($timeout);
6581
6582 my $parser = sub {
6583 my $line = shift;
6584
6585 print "$line\n";
6586
6587 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6588 my ($dev_id, $size, $devname) = ($1, $2, $3);
6589 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
6590 } elsif ($line =~ m/^CTIME: /) {
46f58b5f 6591 # we correctly received the vma config, so we can disable
3cf90d7a
DM
6592 # the timeout now for disk allocation (set to 10 minutes, so
6593 # that we always timeout if something goes wrong)
6594 alarm(600);
91bd6c90
DM
6595 &$print_devmap();
6596 print $fifofh "done\n";
6597 my $tmp = $oldtimeout || 0;
6598 $oldtimeout = undef;
6599 alarm($tmp);
6600 close($fifofh);
6601 }
6602 };
be190583 6603
7c536e11
WB
6604 print "restore vma archive: $dbg_cmdstring\n";
6605 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
91bd6c90
DM
6606 };
6607 my $err = $@;
6608
6609 alarm($oldtimeout) if $oldtimeout;
6610
5f96f4df
WL
6611 my $vollist = [];
6612 foreach my $devname (keys %$devinfo) {
6613 my $volid = $devinfo->{$devname}->{volid};
6614 push @$vollist, $volid if $volid;
6615 }
6616
5f96f4df
WL
6617 PVE::Storage::deactivate_volumes($cfg, $vollist);
6618
91bd6c90
DM
6619 unlink $mapfifo;
6620
6621 if ($err) {
6622 rmtree $tmpdir;
6623 unlink $tmpfn;
6624
91bd6c90
DM
6625 foreach my $devname (keys %$devinfo) {
6626 my $volid = $devinfo->{$devname}->{volid};
6627 next if !$volid;
6628 eval {
6629 if ($volid =~ m|^/|) {
6630 unlink $volid || die 'unlink failed\n';
6631 } else {
6632 PVE::Storage::vdisk_free($cfg, $volid);
6633 }
6634 print STDERR "temporary volume '$volid' sucessfuly removed\n";
6635 };
6636 print STDERR "unable to cleanup '$volid' - $@" if $@;
6637 }
6638 die $err;
6639 }
6640
6641 rmtree $tmpdir;
ed221350
DM
6642
6643 rename($tmpfn, $conffile) ||
91bd6c90
DM
6644 die "unable to commit configuration file '$conffile'\n";
6645
ed221350
DM
6646 PVE::Cluster::cfs_update(); # make sure we read new file
6647
91bd6c90
DM
6648 eval { rescan($vmid, 1); };
6649 warn $@ if $@;
6650}
6651
6652sub restore_tar_archive {
6653 my ($archive, $vmid, $user, $opts) = @_;
6654
9c502e26 6655 if ($archive ne '-') {
ed221350 6656 my $firstfile = tar_archive_read_firstfile($archive);
9c502e26
DM
6657 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6658 if $firstfile ne 'qemu-server.conf';
6659 }
3e16d5fc 6660
20519efc 6661 my $storecfg = PVE::Storage::config();
ebb55558 6662
ed221350 6663 # destroy existing data - keep empty config
ffda963f 6664 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
ebb55558 6665 destroy_vm($storecfg, $vmid, 1) if -f $vmcfgfn;
ed221350 6666
3e16d5fc
DM
6667 my $tocmd = "/usr/lib/qemu-server/qmextract";
6668
2415a446 6669 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
a0d1b1a2 6670 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
3e16d5fc
DM
6671 $tocmd .= ' --prealloc' if $opts->{prealloc};
6672 $tocmd .= ' --info' if $opts->{info};
6673
a0d1b1a2 6674 # tar option "xf" does not autodetect compression when read from STDIN,
9c502e26 6675 # so we pipe to zcat
2415a446
DM
6676 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
6677 PVE::Tools::shellquote("--to-command=$tocmd");
3e16d5fc
DM
6678
6679 my $tmpdir = "/var/tmp/vzdumptmp$$";
6680 mkpath $tmpdir;
6681
6682 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
6683 local $ENV{VZDUMP_VMID} = $vmid;
a0d1b1a2 6684 local $ENV{VZDUMP_USER} = $user;
3e16d5fc 6685
ffda963f 6686 my $conffile = PVE::QemuConfig->config_file($vmid);
3e16d5fc
DM
6687 my $tmpfn = "$conffile.$$.tmp";
6688
6689 # disable interrupts (always do cleanups)
6cb0144a
EK
6690 local $SIG{INT} =
6691 local $SIG{TERM} =
6692 local $SIG{QUIT} =
6693 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
3e16d5fc 6694
afdb31d5 6695 eval {
3e16d5fc 6696 # enable interrupts
6cb0144a
EK
6697 local $SIG{INT} =
6698 local $SIG{TERM} =
6699 local $SIG{QUIT} =
6700 local $SIG{HUP} =
6701 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
3e16d5fc 6702
9c502e26
DM
6703 if ($archive eq '-') {
6704 print "extracting archive from STDIN\n";
6705 run_command($cmd, input => "<&STDIN");
6706 } else {
6707 print "extracting archive '$archive'\n";
6708 run_command($cmd);
6709 }
3e16d5fc
DM
6710
6711 return if $opts->{info};
6712
6713 # read new mapping
6714 my $map = {};
6715 my $statfile = "$tmpdir/qmrestore.stat";
6716 if (my $fd = IO::File->new($statfile, "r")) {
6717 while (defined (my $line = <$fd>)) {
6718 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6719 $map->{$1} = $2 if $1;
6720 } else {
6721 print STDERR "unable to parse line in statfile - $line\n";
6722 }
6723 }
6724 $fd->close();
6725 }
6726
6727 my $confsrc = "$tmpdir/qemu-server.conf";
6728
6729 my $srcfd = new IO::File($confsrc, "r") ||
6730 die "unable to open file '$confsrc'\n";
6731
6732 my $outfd = new IO::File ($tmpfn, "w") ||
6733 die "unable to write config for VM $vmid\n";
6734
91bd6c90 6735 my $cookie = { netcount => 0 };
3e16d5fc 6736 while (defined (my $line = <$srcfd>)) {
be190583 6737 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
3e16d5fc
DM
6738 }
6739
6740 $srcfd->close();
6741 $outfd->close();
6742 };
6743 my $err = $@;
6744
afdb31d5 6745 if ($err) {
3e16d5fc
DM
6746
6747 unlink $tmpfn;
6748
ed221350 6749 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
afdb31d5 6750
3e16d5fc 6751 die $err;
afdb31d5 6752 }
3e16d5fc
DM
6753
6754 rmtree $tmpdir;
6755
6756 rename $tmpfn, $conffile ||
6757 die "unable to commit configuration file '$conffile'\n";
91bd6c90 6758
ed221350
DM
6759 PVE::Cluster::cfs_update(); # make sure we read new file
6760
91bd6c90
DM
6761 eval { rescan($vmid, 1); };
6762 warn $@ if $@;
3e16d5fc
DM
6763};
6764
65a5ce88 6765sub foreach_storage_used_by_vm {
18bfb361
DM
6766 my ($conf, $func) = @_;
6767
6768 my $sidhash = {};
6769
8ddbcf8b
FG
6770 foreach_drive($conf, sub {
6771 my ($ds, $drive) = @_;
6772 return if drive_is_cdrom($drive);
18bfb361
DM
6773
6774 my $volid = $drive->{file};
6775
6776 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
be190583 6777 $sidhash->{$sid} = $sid if $sid;
8ddbcf8b 6778 });
18bfb361
DM
6779
6780 foreach my $sid (sort keys %$sidhash) {
6781 &$func($sid);
6782 }
6783}
6784
e5eaa028
WL
6785sub do_snapshots_with_qemu {
6786 my ($storecfg, $volid) = @_;
6787
6788 my $storage_name = PVE::Storage::parse_volume_id($volid);
8aa2ed7c 6789 my $scfg = $storecfg->{ids}->{$storage_name};
e5eaa028 6790
8aa2ed7c 6791 if ($qemu_snap_storage->{$scfg->{type}} && !$scfg->{krbd}){
e5eaa028
WL
6792 return 1;
6793 }
6794
6795 if ($volid =~ m/\.(qcow2|qed)$/){
6796 return 1;
6797 }
6798
6799 return undef;
6800}
6801
4dcc780c 6802sub qga_check_running {
a4938c72 6803 my ($vmid, $nowarn) = @_;
4dcc780c
WL
6804
6805 eval { vm_mon_cmd($vmid, "guest-ping", timeout => 3); };
6806 if ($@) {
a4938c72 6807 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
4dcc780c
WL
6808 return 0;
6809 }
6810 return 1;
6811}
6812
04a69bb4
AD
6813sub template_create {
6814 my ($vmid, $conf, $disk) = @_;
6815
04a69bb4 6816 my $storecfg = PVE::Storage::config();
04a69bb4 6817
9cd07842
DM
6818 foreach_drive($conf, sub {
6819 my ($ds, $drive) = @_;
6820
6821 return if drive_is_cdrom($drive);
6822 return if $disk && $ds ne $disk;
6823
6824 my $volid = $drive->{file};
bbd56097 6825 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
9cd07842 6826
04a69bb4
AD
6827 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
6828 $drive->{file} = $voliddst;
152fe752 6829 $conf->{$ds} = print_drive($vmid, $drive);
ffda963f 6830 PVE::QemuConfig->write_config($vmid, $conf);
04a69bb4 6831 });
04a69bb4
AD
6832}
6833
92bdc3f0
DC
6834sub convert_iscsi_path {
6835 my ($path) = @_;
6836
6837 if ($path =~ m|^iscsi://([^/]+)/([^/]+)/(.+)$|) {
6838 my $portal = $1;
6839 my $target = $2;
6840 my $lun = $3;
6841
6842 my $initiator_name = get_initiator_name();
6843
6844 return "file.driver=iscsi,file.transport=tcp,file.initiator-name=$initiator_name,".
6845 "file.portal=$portal,file.target=$target,file.lun=$lun,driver=raw";
6846 }
6847
6848 die "cannot convert iscsi path '$path', unkown format\n";
6849}
6850
5133de42 6851sub qemu_img_convert {
988e2714 6852 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5133de42
AD
6853
6854 my $storecfg = PVE::Storage::config();
6855 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
6856 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
6857
6858 if ($src_storeid && $dst_storeid) {
6bb91c17
DM
6859
6860 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
6861
5133de42
AD
6862 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
6863 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
6864
6865 my $src_format = qemu_img_format($src_scfg, $src_volname);
6866 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
6867
6868 my $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
6869 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
6870
92bdc3f0
DC
6871 my $src_is_iscsi = ($src_path =~ m|^iscsi://|);
6872 my $dst_is_iscsi = ($dst_path =~ m|^iscsi://|);
6873
5133de42 6874 my $cmd = [];
eed24303 6875 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
29004a20 6876 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
d4940091
FG
6877 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
6878 push @$cmd, '-T', 'none' if $src_scfg->{type} eq 'zfspool';
92bdc3f0
DC
6879
6880 if ($src_is_iscsi) {
6881 push @$cmd, '--image-opts';
6882 $src_path = convert_iscsi_path($src_path);
6883 } else {
6884 push @$cmd, '-f', $src_format;
6885 }
6886
6887 if ($dst_is_iscsi) {
6888 push @$cmd, '--target-image-opts';
6889 $dst_path = convert_iscsi_path($dst_path);
6890 } else {
6891 push @$cmd, '-O', $dst_format;
6892 }
6893
6894 push @$cmd, $src_path;
6895
6896 if (!$dst_is_iscsi && $is_zero_initialized) {
988e2714
WB
6897 push @$cmd, "zeroinit:$dst_path";
6898 } else {
6899 push @$cmd, $dst_path;
6900 }
5133de42
AD
6901
6902 my $parser = sub {
6903 my $line = shift;
6904 if($line =~ m/\((\S+)\/100\%\)/){
6905 my $percent = $1;
6906 my $transferred = int($size * $percent / 100);
6907 my $remaining = $size - $transferred;
6908
6909 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6910 }
6911
6912 };
6913
6914 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
6915 my $err = $@;
6916 die "copy failed: $err" if $err;
6917 }
6918}
6919
6920sub qemu_img_format {
6921 my ($scfg, $volname) = @_;
6922
9c52f5ed 6923 if ($scfg->{path} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
5133de42 6924 return $1;
be190583 6925 } else {
5133de42 6926 return "raw";
5133de42
AD
6927 }
6928}
6929
cfad42af 6930sub qemu_drive_mirror {
9fa05d31 6931 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
cfad42af 6932
5a345967
AD
6933 $jobs = {} if !$jobs;
6934
6935 my $qemu_target;
6936 my $format;
35e4ab04 6937 $jobs->{"drive-$drive"} = {};
152fe752 6938
1e5143de 6939 if ($dst_volid =~ /^nbd:/) {
87955688 6940 $qemu_target = $dst_volid;
5a345967 6941 $format = "nbd";
5a345967 6942 } else {
5a345967
AD
6943 my $storecfg = PVE::Storage::config();
6944 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
6945
6946 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
cfad42af 6947
5a345967 6948 $format = qemu_img_format($dst_scfg, $dst_volname);
21ccdb50 6949
5a345967 6950 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
21ccdb50 6951
5a345967
AD
6952 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
6953 }
988e2714
WB
6954
6955 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
88383920
DM
6956 $opts->{format} = $format if $format;
6957
9fa05d31 6958 if (defined($bwlimit)) {
f6409f61
TL
6959 $opts->{speed} = $bwlimit * 1024;
6960 print "drive mirror is starting for drive-$drive with bandwidth limit: ${bwlimit} KB/s\n";
9fa05d31
SI
6961 } else {
6962 print "drive mirror is starting for drive-$drive\n";
6963 }
21ccdb50 6964
6dde5ea2
TL
6965 # if a job already runs for this device we get an error, catch it for cleanup
6966 eval { vm_mon_cmd($vmid, "drive-mirror", %$opts); };
5a345967
AD
6967 if (my $err = $@) {
6968 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6dde5ea2
TL
6969 warn "$@\n" if $@;
6970 die "mirroring error: $err\n";
5a345967
AD
6971 }
6972
5619e74a 6973 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
5a345967
AD
6974}
6975
6976sub qemu_drive_mirror_monitor {
5619e74a 6977 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
2e953867 6978
08ac653f 6979 eval {
5a345967
AD
6980 my $err_complete = 0;
6981
08ac653f 6982 while (1) {
5a345967
AD
6983 die "storage migration timed out\n" if $err_complete > 300;
6984
08ac653f 6985 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
08ac653f 6986
5a345967
AD
6987 my $running_mirror_jobs = {};
6988 foreach my $stat (@$stats) {
6989 next if $stat->{type} ne 'mirror';
6990 $running_mirror_jobs->{$stat->{device}} = $stat;
6991 }
08ac653f 6992
5a345967 6993 my $readycounter = 0;
67fb9de6 6994
5a345967
AD
6995 foreach my $job (keys %$jobs) {
6996
6997 if(defined($jobs->{$job}->{complete}) && !defined($running_mirror_jobs->{$job})) {
6998 print "$job : finished\n";
6999 delete $jobs->{$job};
7000 next;
7001 }
7002
bd2d5fe6 7003 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
f34ebd52 7004
5a345967
AD
7005 my $busy = $running_mirror_jobs->{$job}->{busy};
7006 my $ready = $running_mirror_jobs->{$job}->{ready};
7007 if (my $total = $running_mirror_jobs->{$job}->{len}) {
7008 my $transferred = $running_mirror_jobs->{$job}->{offset} || 0;
7009 my $remaining = $total - $transferred;
7010 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
08ac653f 7011
5a345967
AD
7012 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
7013 }
f34ebd52 7014
d1782eba 7015 $readycounter++ if $running_mirror_jobs->{$job}->{ready};
5a345967 7016 }
b467f79a 7017
5a345967
AD
7018 last if scalar(keys %$jobs) == 0;
7019
7020 if ($readycounter == scalar(keys %$jobs)) {
7021 print "all mirroring jobs are ready \n";
7022 last if $skipcomplete; #do the complete later
7023
7024 if ($vmiddst && $vmiddst != $vmid) {
1a988fd2
DC
7025 my $agent_running = $qga && qga_check_running($vmid);
7026 if ($agent_running) {
5619e74a
AD
7027 print "freeze filesystem\n";
7028 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-freeze"); };
7029 } else {
7030 print "suspend vm\n";
7031 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
7032 }
7033
5a345967
AD
7034 # if we clone a disk for a new target vm, we don't switch the disk
7035 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
5619e74a 7036
1a988fd2 7037 if ($agent_running) {
5619e74a
AD
7038 print "unfreeze filesystem\n";
7039 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-thaw"); };
7040 } else {
7041 print "resume vm\n";
7042 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
7043 }
7044
2e953867 7045 last;
5a345967
AD
7046 } else {
7047
7048 foreach my $job (keys %$jobs) {
7049 # try to switch the disk if source and destination are on the same guest
bd2d5fe6 7050 print "$job: Completing block job...\n";
5a345967
AD
7051
7052 eval { vm_mon_cmd($vmid, "block-job-complete", device => $job) };
7053 if ($@ =~ m/cannot be completed/) {
bd2d5fe6 7054 print "$job: Block job cannot be completed, try again.\n";
5a345967
AD
7055 $err_complete++;
7056 }else {
bd2d5fe6 7057 print "$job: Completed successfully.\n";
5a345967
AD
7058 $jobs->{$job}->{complete} = 1;
7059 }
7060 }
2e953867 7061 }
08ac653f 7062 }
08ac653f 7063 sleep 1;
cfad42af 7064 }
08ac653f 7065 };
88383920 7066 my $err = $@;
08ac653f 7067
88383920 7068 if ($err) {
5a345967 7069 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
88383920
DM
7070 die "mirroring error: $err";
7071 }
7072
5a345967
AD
7073}
7074
7075sub qemu_blockjobs_cancel {
7076 my ($vmid, $jobs) = @_;
7077
7078 foreach my $job (keys %$jobs) {
bd2d5fe6 7079 print "$job: Cancelling block job\n";
5a345967
AD
7080 eval { vm_mon_cmd($vmid, "block-job-cancel", device => $job); };
7081 $jobs->{$job}->{cancel} = 1;
7082 }
7083
7084 while (1) {
7085 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
7086
7087 my $running_jobs = {};
7088 foreach my $stat (@$stats) {
7089 $running_jobs->{$stat->{device}} = $stat;
7090 }
7091
7092 foreach my $job (keys %$jobs) {
7093
bd2d5fe6
WB
7094 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
7095 print "$job: Done.\n";
5a345967
AD
7096 delete $jobs->{$job};
7097 }
7098 }
7099
7100 last if scalar(keys %$jobs) == 0;
7101
7102 sleep 1;
cfad42af
AD
7103 }
7104}
7105
152fe752 7106sub clone_disk {
be190583 7107 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
7e303ef3 7108 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga, $bwlimit) = @_;
152fe752
DM
7109
7110 my $newvolid;
7111
7112 if (!$full) {
7113 print "create linked clone of drive $drivename ($drive->{file})\n";
258e646c 7114 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
152fe752
DM
7115 push @$newvollist, $newvolid;
7116 } else {
5a345967 7117
152fe752
DM
7118 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
7119 $storeid = $storage if $storage;
7120
44549149 7121 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
152fe752
DM
7122 my ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 3);
7123
7124 print "create full clone of drive $drivename ($drive->{file})\n";
931432bd
WB
7125 my $name = undef;
7126 if (drive_is_cloudinit($drive)) {
7127 $name = "vm-$newvmid-cloudinit";
8fa6a851 7128 $snapname = undef;
a3570921 7129 # we only get here if it's supported by QEMU_FORMAT_RE, so just accept
e1afab6e
ML
7130 if ($dst_format ne 'raw') {
7131 $name .= ".$dst_format";
931432bd
WB
7132 }
7133 }
7134 $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
152fe752
DM
7135 push @$newvollist, $newvolid;
7136
3999f370 7137 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
1dbd6d30 7138
988e2714 7139 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
152fe752 7140 if (!$running || $snapname) {
d189e590 7141 # TODO: handle bwlimits
988e2714 7142 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
152fe752 7143 } else {
2e541679
AD
7144
7145 my $kvmver = get_running_qemu_version ($vmid);
7146 if (!qemu_machine_feature_enabled (undef, $kvmver, 2, 7)) {
961af8a3
WB
7147 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
7148 if $drive->{iothread};
2e541679 7149 }
2af848a2 7150
7e303ef3 7151 qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga, $bwlimit);
be190583 7152 }
152fe752
DM
7153 }
7154
7155 my ($size) = PVE::Storage::volume_size_info($storecfg, $newvolid, 3);
7156
7157 my $disk = $drive;
7158 $disk->{format} = undef;
7159 $disk->{file} = $newvolid;
7160 $disk->{size} = $size;
7161
7162 return $disk;
7163}
7164
ff556cf2
DM
7165# this only works if VM is running
7166sub get_current_qemu_machine {
7167 my ($vmid) = @_;
7168
7169 my $cmd = { execute => 'query-machines', arguments => {} };
8e90138a 7170 my $res = vm_qmp_command($vmid, $cmd);
ff556cf2
DM
7171
7172 my ($current, $default);
7173 foreach my $e (@$res) {
7174 $default = $e->{name} if $e->{'is-default'};
7175 $current = $e->{name} if $e->{'is-current'};
7176 }
7177
7178 # fallback to the default machine if current is not supported by qemu
7179 return $current || $default || 'pc';
7180}
7181
98cfd8b6
AD
7182sub get_running_qemu_version {
7183 my ($vmid) = @_;
7184 my $cmd = { execute => 'query-version', arguments => {} };
7185 my $res = vm_qmp_command($vmid, $cmd);
7186 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
7187}
7188
23f73120
AD
7189sub qemu_machine_feature_enabled {
7190 my ($machine, $kvmver, $version_major, $version_minor) = @_;
7191
7192 my $current_major;
7193 my $current_minor;
7194
d731ecbe 7195 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
23f73120
AD
7196
7197 $current_major = $3;
7198 $current_minor = $4;
7199
7200 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
7201
7202 $current_major = $1;
7203 $current_minor = $2;
7204 }
7205
dd84e5ec
WB
7206 return 1 if $current_major > $version_major ||
7207 ($current_major == $version_major &&
7208 $current_minor >= $version_minor);
23f73120
AD
7209}
7210
42dbd2ee 7211sub qemu_machine_pxe {
8071149b 7212 my ($vmid, $conf) = @_;
42dbd2ee 7213
8071149b 7214 my $machine = PVE::QemuServer::get_current_qemu_machine($vmid);
42dbd2ee 7215
3807f3e4
DC
7216 if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
7217 $machine .= '.pxe';
42dbd2ee
AD
7218 }
7219
d1363934 7220 return $machine;
42dbd2ee
AD
7221}
7222
249c4a6c
AD
7223sub qemu_use_old_bios_files {
7224 my ($machine_type) = @_;
7225
7226 return if !$machine_type;
7227
7228 my $use_old_bios_files = undef;
7229
7230 if ($machine_type =~ m/^(\S+)\.pxe$/) {
7231 $machine_type = $1;
7232 $use_old_bios_files = 1;
7233 } else {
74cc511f 7234 my $kvmver = kvm_user_version();
249c4a6c
AD
7235 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
7236 # load new efi bios files on migration. So this hack is required to allow
7237 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
7238 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
74cc511f 7239 $use_old_bios_files = !qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 4);
249c4a6c
AD
7240 }
7241
7242 return ($use_old_bios_files, $machine_type);
7243}
7244
96ed3574
WB
7245sub create_efidisk($$$$$) {
7246 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
3e1f1122 7247
96ed3574
WB
7248 my (undef, $ovmf_vars) = get_ovmf_files($arch);
7249 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
3e1f1122 7250
96ed3574 7251 my $vars_size = PVE::Tools::convert_size(-s $ovmf_vars, 'b' => 'kb');
3e1f1122
TL
7252 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
7253 PVE::Storage::activate_volumes($storecfg, [$volid]);
7254
7255 my $path = PVE::Storage::path($storecfg, $volid);
7256 eval {
96ed3574 7257 run_command(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
3e1f1122
TL
7258 };
7259 die "Copying EFI vars image failed: $@" if $@;
7260
7261 return ($volid, $vars_size);
7262}
7263
22de899a
AD
7264sub vm_iothreads_list {
7265 my ($vmid) = @_;
7266
7267 my $res = vm_mon_cmd($vmid, 'query-iothreads');
7268
7269 my $iothreads = {};
7270 foreach my $iothread (@$res) {
7271 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
7272 }
7273
7274 return $iothreads;
7275}
7276
ee034f5c
AD
7277sub scsihw_infos {
7278 my ($conf, $drive) = @_;
7279
7280 my $maxdev = 0;
7281
7fe1b688 7282 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
ee034f5c 7283 $maxdev = 7;
a1511b3c 7284 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
ee034f5c
AD
7285 $maxdev = 1;
7286 } else {
7287 $maxdev = 256;
7288 }
7289
7290 my $controller = int($drive->{index} / $maxdev);
a1511b3c 7291 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') ? "virtioscsi" : "scsihw";
ee034f5c
AD
7292
7293 return ($maxdev, $controller, $controller_prefix);
7294}
a1511b3c 7295
075e8249 7296sub add_hyperv_enlightenments {
2894c247 7297 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
4317f69f 7298
4317f69f
AD
7299 return if $winversion < 6;
7300 return if $bios && $bios eq 'ovmf' && $winversion < 8;
7301
2894c247
DC
7302 if ($gpu_passthrough || defined($hv_vendor_id)) {
7303 $hv_vendor_id //= 'proxmox';
7304 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
7305 }
5aba3953 7306
4317f69f
AD
7307 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
7308 push @$cpuFlags , 'hv_spinlocks=0x1fff';
7309 push @$cpuFlags , 'hv_vapic';
7310 push @$cpuFlags , 'hv_time';
7311 } else {
7312 push @$cpuFlags , 'hv_spinlocks=0xffff';
7313 }
7314
7315 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 6)) {
7316 push @$cpuFlags , 'hv_reset';
7317 push @$cpuFlags , 'hv_vpindex';
7318 push @$cpuFlags , 'hv_runtime';
7319 }
7320
7321 if ($winversion >= 7) {
7322 push @$cpuFlags , 'hv_relaxed';
ebb346d6 7323
df648a6a 7324 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 12)) {
ebb346d6
AD
7325 push @$cpuFlags , 'hv_synic';
7326 push @$cpuFlags , 'hv_stimer';
7327 }
392dfbf5 7328
392dfbf5
SR
7329 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 3, 1)) {
7330 push @$cpuFlags , 'hv_ipi';
392dfbf5 7331 }
4317f69f
AD
7332 }
7333}
7334
7335sub windows_version {
7336 my ($ostype) = @_;
7337
7338 return 0 if !$ostype;
7339
7340 my $winversion = 0;
7341
7342 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
7343 $winversion = 5;
7344 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
7345 $winversion = 6;
7346 } elsif ($ostype =~ m/^win(\d+)$/) {
7347 $winversion = $1;
7348 }
7349
7350 return $winversion;
7351}
7352
44549149
EK
7353sub resolve_dst_disk_format {
7354 my ($storecfg, $storeid, $src_volname, $format) = @_;
7355 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
7356
7357 if (!$format) {
7358 # if no target format is specified, use the source disk format as hint
7359 if ($src_volname) {
7360 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
7361 $format = qemu_img_format($scfg, $src_volname);
7362 } else {
7363 return $defFormat;
7364 }
7365 }
7366
7367 # test if requested format is supported - else use default
7368 my $supported = grep { $_ eq $format } @$validFormats;
7369 $format = $defFormat if !$supported;
7370 return $format;
7371}
7372
ae2fcb3b
EK
7373sub resolve_first_disk {
7374 my $conf = shift;
7375 my @disks = PVE::QemuServer::valid_drive_names();
7376 my $firstdisk;
7377 foreach my $ds (reverse @disks) {
7378 next if !$conf->{$ds};
7379 my $disk = PVE::QemuServer::parse_drive($ds, $conf->{$ds});
7380 next if PVE::QemuServer::drive_is_cdrom($disk);
7381 $firstdisk = $ds;
7382 }
7383 return $firstdisk;
7384}
7385
6ee499ff 7386sub generate_uuid {
ae2fcb3b
EK
7387 my ($uuid, $uuid_str);
7388 UUID::generate($uuid);
7389 UUID::unparse($uuid, $uuid_str);
6ee499ff
DC
7390 return $uuid_str;
7391}
7392
7393sub generate_smbios1_uuid {
7394 return "uuid=".generate_uuid();
ae2fcb3b
EK
7395}
7396
9c152e87
TL
7397sub nbd_stop {
7398 my ($vmid) = @_;
7399
7400 vm_mon_cmd($vmid, 'nbd-server-stop');
7401}
7402
65e866e5
DM
7403# bash completion helper
7404
7405sub complete_backup_archives {
7406 my ($cmdname, $pname, $cvalue) = @_;
7407
7408 my $cfg = PVE::Storage::config();
7409
7410 my $storeid;
7411
7412 if ($cvalue =~ m/^([^:]+):/) {
7413 $storeid = $1;
7414 }
7415
7416 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
7417
7418 my $res = [];
7419 foreach my $id (keys %$data) {
7420 foreach my $item (@{$data->{$id}}) {
7421 next if $item->{format} !~ m/^vma\.(gz|lzo)$/;
7422 push @$res, $item->{volid} if defined($item->{volid});
7423 }
7424 }
7425
7426 return $res;
7427}
7428
7429my $complete_vmid_full = sub {
7430 my ($running) = @_;
7431
7432 my $idlist = vmstatus();
7433
7434 my $res = [];
7435
7436 foreach my $id (keys %$idlist) {
7437 my $d = $idlist->{$id};
7438 if (defined($running)) {
7439 next if $d->{template};
7440 next if $running && $d->{status} ne 'running';
7441 next if !$running && $d->{status} eq 'running';
7442 }
7443 push @$res, $id;
7444
7445 }
7446 return $res;
7447};
7448
7449sub complete_vmid {
7450 return &$complete_vmid_full();
7451}
7452
7453sub complete_vmid_stopped {
7454 return &$complete_vmid_full(0);
7455}
7456
7457sub complete_vmid_running {
7458 return &$complete_vmid_full(1);
7459}
7460
335af808
DM
7461sub complete_storage {
7462
7463 my $cfg = PVE::Storage::config();
7464 my $ids = $cfg->{ids};
7465
7466 my $res = [];
7467 foreach my $sid (keys %$ids) {
7468 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
c4c844ef 7469 next if !$ids->{$sid}->{content}->{images};
335af808
DM
7470 push @$res, $sid;
7471 }
7472
7473 return $res;
7474}
7475
1e3baf05 74761;