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