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