]> git.proxmox.com Git - qemu-server.git/blame - PVE/QemuServer.pm
allow explicit set vga with gpu passthrough
[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
DM
5374sub vm_commandline {
5375 my ($storecfg, $vmid) = @_;
5376
ffda963f 5377 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05
DM
5378
5379 my $defaults = load_defaults();
5380
6b64503e 5381 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
1e3baf05 5382
5930c1ff 5383 return PVE::Tools::cmd2string($cmd);
1e3baf05
DM
5384}
5385
5386sub vm_reset {
5387 my ($vmid, $skiplock) = @_;
5388
ffda963f 5389 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5390
ffda963f 5391 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5392
ffda963f 5393 PVE::QemuConfig->check_lock($conf) if !$skiplock;
1e3baf05 5394
816e2c4a 5395 vm_mon_cmd($vmid, "system_reset");
ff1a2432
DM
5396 });
5397}
5398
5399sub get_vm_volumes {
5400 my ($conf) = @_;
1e3baf05 5401
ff1a2432 5402 my $vollist = [];
d5769dc2 5403 foreach_volid($conf, sub {
392f8b5d 5404 my ($volid, $attr) = @_;
ff1a2432 5405
d5769dc2 5406 return if $volid =~ m|^/|;
ff1a2432 5407
d5769dc2
DM
5408 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5409 return if !$sid;
ff1a2432
DM
5410
5411 push @$vollist, $volid;
1e3baf05 5412 });
ff1a2432
DM
5413
5414 return $vollist;
5415}
5416
5417sub vm_stop_cleanup {
70b04821 5418 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
ff1a2432 5419
745fed70 5420 eval {
ff1a2432 5421
254575e9
DM
5422 if (!$keepActive) {
5423 my $vollist = get_vm_volumes($conf);
5424 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5425 }
a1b7d579 5426
ab6a046f 5427 foreach my $ext (qw(mon qmp pid vnc qga)) {
961bfcb2
DM
5428 unlink "/var/run/qemu-server/${vmid}.$ext";
5429 }
a1b7d579 5430
6ab45bd7
DC
5431 foreach my $key (keys %$conf) {
5432 next if $key !~ m/^hostpci(\d+)$/;
5433 my $hostpciindex = $1;
5434 my $d = parse_hostpci($conf->{$key});
5435 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $hostpciindex);
5436
5437 foreach my $pci (@{$d->{pciid}}) {
2fd24788 5438 my $pciid = $pci->{id};
6ab45bd7
DC
5439 PVE::SysFSTools::pci_cleanup_mdev_device($pciid, $uuid);
5440 }
5441 }
5442
70b04821 5443 vmconfig_apply_pending($vmid, $conf, $storecfg) if $apply_pending_changes;
745fed70
DM
5444 };
5445 warn $@ if $@; # avoid errors - just warn
1e3baf05
DM
5446}
5447
e6c3b671 5448# Note: use $nockeck to skip tests if VM configuration file exists.
254575e9
DM
5449# We need that when migration VMs to other nodes (files already moved)
5450# Note: we set $keepActive in vzdump stop mode - volumes need to stay active
1e3baf05 5451sub vm_stop {
af30308f 5452 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
9269013a 5453
9269013a 5454 $force = 1 if !defined($force) && !$shutdown;
1e3baf05 5455
af30308f
DM
5456 if ($migratedfrom){
5457 my $pid = check_running($vmid, $nocheck, $migratedfrom);
5458 kill 15, $pid if $pid;
ffda963f 5459 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
70b04821 5460 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 0);
af30308f
DM
5461 return;
5462 }
5463
ffda963f 5464 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5465
e6c3b671 5466 my $pid = check_running($vmid, $nocheck);
ff1a2432 5467 return if !$pid;
1e3baf05 5468
ff1a2432 5469 my $conf;
e6c3b671 5470 if (!$nocheck) {
ffda963f
FG
5471 $conf = PVE::QemuConfig->load_config($vmid);
5472 PVE::QemuConfig->check_lock($conf) if !$skiplock;
7f4a5b5a 5473 if (!defined($timeout) && $shutdown && $conf->{startup}) {
38f7f26c 5474 my $opts = PVE::JSONSchema::pve_parse_startup_order($conf->{startup});
7f4a5b5a
DM
5475 $timeout = $opts->{down} if $opts->{down};
5476 }
e6c3b671 5477 }
19672434 5478
7f4a5b5a 5479 $timeout = 60 if !defined($timeout);
67fb9de6 5480
9269013a
DM
5481 eval {
5482 if ($shutdown) {
9d66b397 5483 if (defined($conf) && parse_guest_agent($conf)->{enabled}) {
2ea54503 5484 vm_qmp_command($vmid, { execute => "guest-shutdown" }, $nocheck);
1c0c1c17 5485 } else {
2ea54503 5486 vm_qmp_command($vmid, { execute => "system_powerdown" }, $nocheck);
1c0c1c17 5487 }
9269013a 5488 } else {
2ea54503 5489 vm_qmp_command($vmid, { execute => "quit" }, $nocheck);
afdb31d5 5490 }
9269013a 5491 };
1e3baf05
DM
5492 my $err = $@;
5493
5494 if (!$err) {
1e3baf05 5495 my $count = 0;
e6c3b671 5496 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
5497 $count++;
5498 sleep 1;
5499 }
5500
5501 if ($count >= $timeout) {
9269013a
DM
5502 if ($force) {
5503 warn "VM still running - terminating now with SIGTERM\n";
5504 kill 15, $pid;
5505 } else {
5506 die "VM quit/powerdown failed - got timeout\n";
5507 }
5508 } else {
70b04821 5509 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
9269013a 5510 return;
1e3baf05
DM
5511 }
5512 } else {
9269013a
DM
5513 if ($force) {
5514 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5515 kill 15, $pid;
5516 } else {
afdb31d5 5517 die "VM quit/powerdown failed\n";
9269013a 5518 }
1e3baf05
DM
5519 }
5520
5521 # wait again
ff1a2432 5522 $timeout = 10;
1e3baf05
DM
5523
5524 my $count = 0;
e6c3b671 5525 while (($count < $timeout) && check_running($vmid, $nocheck)) {
1e3baf05
DM
5526 $count++;
5527 sleep 1;
5528 }
5529
5530 if ($count >= $timeout) {
ff1a2432 5531 warn "VM still running - terminating now with SIGKILL\n";
1e3baf05 5532 kill 9, $pid;
ff1a2432 5533 sleep 1;
1e3baf05
DM
5534 }
5535
70b04821 5536 vm_stop_cleanup($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
ff1a2432 5537 });
1e3baf05
DM
5538}
5539
5540sub vm_suspend {
5541 my ($vmid, $skiplock) = @_;
5542
ffda963f 5543 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5544
ffda963f 5545 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5546
e79706d4
FG
5547 PVE::QemuConfig->check_lock($conf)
5548 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
bcb7c9cf 5549
f77f91f3 5550 vm_mon_cmd($vmid, "stop");
1e3baf05
DM
5551 });
5552}
5553
5554sub vm_resume {
289e0b85 5555 my ($vmid, $skiplock, $nocheck) = @_;
1e3baf05 5556
ffda963f 5557 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5558
c2786bed
DC
5559 my $res = vm_mon_cmd($vmid, 'query-status');
5560 my $resume_cmd = 'cont';
5561
5562 if ($res->{status} && $res->{status} eq 'suspended') {
5563 $resume_cmd = 'system_wakeup';
5564 }
5565
289e0b85 5566 if (!$nocheck) {
1e3baf05 5567
ffda963f 5568 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5569
e79706d4
FG
5570 PVE::QemuConfig->check_lock($conf)
5571 if !($skiplock || PVE::QemuConfig->has_lock($conf, 'backup'));
289e0b85 5572
c2786bed 5573 vm_mon_cmd($vmid, $resume_cmd);
289e0b85
AD
5574
5575 } else {
c2786bed 5576 vm_mon_cmd_nocheck($vmid, $resume_cmd);
289e0b85 5577 }
1e3baf05
DM
5578 });
5579}
5580
5fdbe4f0
DM
5581sub vm_sendkey {
5582 my ($vmid, $skiplock, $key) = @_;
1e3baf05 5583
ffda963f 5584 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5585
ffda963f 5586 my $conf = PVE::QemuConfig->load_config($vmid);
f5eb281a 5587
7b7c6d1b
DM
5588 # there is no qmp command, so we use the human monitor command
5589 vm_human_monitor_command($vmid, "sendkey $key");
1e3baf05
DM
5590 });
5591}
5592
5593sub vm_destroy {
5594 my ($storecfg, $vmid, $skiplock) = @_;
5595
ffda963f 5596 PVE::QemuConfig->lock_config($vmid, sub {
1e3baf05 5597
ffda963f 5598 my $conf = PVE::QemuConfig->load_config($vmid);
1e3baf05 5599
ff1a2432 5600 if (!check_running($vmid)) {
15cc8784 5601 destroy_vm($storecfg, $vmid, undef, $skiplock);
ff1a2432
DM
5602 } else {
5603 die "VM $vmid is running - destroy failed\n";
1e3baf05
DM
5604 }
5605 });
5606}
5607
3e16d5fc
DM
5608# vzdump restore implementaion
5609
ed221350 5610sub tar_archive_read_firstfile {
3e16d5fc 5611 my $archive = shift;
afdb31d5 5612
3e16d5fc
DM
5613 die "ERROR: file '$archive' does not exist\n" if ! -f $archive;
5614
5615 # try to detect archive type first
387ba257 5616 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
3e16d5fc 5617 die "unable to open file '$archive'\n";
387ba257 5618 my $firstfile = <$fh>;
3e16d5fc 5619 kill 15, $pid;
387ba257 5620 close $fh;
3e16d5fc
DM
5621
5622 die "ERROR: archive contaions no data\n" if !$firstfile;
5623 chomp $firstfile;
5624
5625 return $firstfile;
5626}
5627
ed221350
DM
5628sub tar_restore_cleanup {
5629 my ($storecfg, $statfile) = @_;
3e16d5fc
DM
5630
5631 print STDERR "starting cleanup\n";
5632
5633 if (my $fd = IO::File->new($statfile, "r")) {
5634 while (defined(my $line = <$fd>)) {
5635 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5636 my $volid = $2;
5637 eval {
5638 if ($volid =~ m|^/|) {
5639 unlink $volid || die 'unlink failed\n';
5640 } else {
ed221350 5641 PVE::Storage::vdisk_free($storecfg, $volid);
3e16d5fc 5642 }
afdb31d5 5643 print STDERR "temporary volume '$volid' sucessfuly removed\n";
3e16d5fc
DM
5644 };
5645 print STDERR "unable to cleanup '$volid' - $@" if $@;
5646 } else {
5647 print STDERR "unable to parse line in statfile - $line";
afdb31d5 5648 }
3e16d5fc
DM
5649 }
5650 $fd->close();
5651 }
5652}
5653
5654sub restore_archive {
a0d1b1a2 5655 my ($archive, $vmid, $user, $opts) = @_;
3e16d5fc 5656
91bd6c90
DM
5657 my $format = $opts->{format};
5658 my $comp;
5659
5660 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5661 $format = 'tar' if !$format;
5662 $comp = 'gzip';
5663 } elsif ($archive =~ m/\.tar$/) {
5664 $format = 'tar' if !$format;
5665 } elsif ($archive =~ m/.tar.lzo$/) {
5666 $format = 'tar' if !$format;
5667 $comp = 'lzop';
5668 } elsif ($archive =~ m/\.vma$/) {
5669 $format = 'vma' if !$format;
5670 } elsif ($archive =~ m/\.vma\.gz$/) {
5671 $format = 'vma' if !$format;
5672 $comp = 'gzip';
5673 } elsif ($archive =~ m/\.vma\.lzo$/) {
5674 $format = 'vma' if !$format;
5675 $comp = 'lzop';
5676 } else {
5677 $format = 'vma' if !$format; # default
5678 }
5679
5680 # try to detect archive format
5681 if ($format eq 'tar') {
5682 return restore_tar_archive($archive, $vmid, $user, $opts);
5683 } else {
5684 return restore_vma_archive($archive, $vmid, $user, $opts, $comp);
5685 }
5686}
5687
5688sub restore_update_config_line {
5689 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5690
5691 return if $line =~ m/^\#qmdump\#/;
5692 return if $line =~ m/^\#vzdump\#/;
5693 return if $line =~ m/^lock:/;
5694 return if $line =~ m/^unused\d+:/;
5695 return if $line =~ m/^parent:/;
ca3e4fa4 5696 return if $line =~ m/^template:/; # restored VM is never a template
91bd6c90 5697
b5b99790 5698 my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');
91bd6c90
DM
5699 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5700 # try to convert old 1.X settings
5701 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5702 foreach my $devconfig (PVE::Tools::split_list($ethcfg)) {
5703 my ($model, $macaddr) = split(/\=/, $devconfig);
b5b99790 5704 $macaddr = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if !$macaddr || $unique;
91bd6c90
DM
5705 my $net = {
5706 model => $model,
5707 bridge => "vmbr$ind",
5708 macaddr => $macaddr,
5709 };
5710 my $netstr = print_net($net);
5711
5712 print $outfd "net$cookie->{netcount}: $netstr\n";
5713 $cookie->{netcount}++;
5714 }
5715 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5716 my ($id, $netstr) = ($1, $2);
5717 my $net = parse_net($netstr);
b5b99790 5718 $net->{macaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix}) if $net->{macaddr};
91bd6c90
DM
5719 $netstr = print_net($net);
5720 print $outfd "$id: $netstr\n";
6470743f 5721 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
91bd6c90 5722 my $virtdev = $1;
907ea891 5723 my $value = $3;
d9faf790
WB
5724 my $di = parse_drive($virtdev, $value);
5725 if (defined($di->{backup}) && !$di->{backup}) {
91bd6c90 5726 print $outfd "#$line";
c0f7406e 5727 } elsif ($map->{$virtdev}) {
8fd57431 5728 delete $di->{format}; # format can change on restore
91bd6c90 5729 $di->{file} = $map->{$virtdev};
ed221350 5730 $value = print_drive($vmid, $di);
91bd6c90
DM
5731 print $outfd "$virtdev: $value\n";
5732 } else {
5733 print $outfd $line;
5734 }
1a0c2f03 5735 } elsif (($line =~ m/^vmgenid: (.*)/)) {
babecffe 5736 my $vmgenid = $1;
6ee499ff 5737 if ($vmgenid ne '0') {
1a0c2f03 5738 # always generate a new vmgenid if there was a valid one setup
6ee499ff
DC
5739 $vmgenid = generate_uuid();
5740 }
1a0c2f03 5741 print $outfd "vmgenid: $vmgenid\n";
19a5dd55
WL
5742 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5743 my ($uuid, $uuid_str);
5744 UUID::generate($uuid);
5745 UUID::unparse($uuid, $uuid_str);
5746 my $smbios1 = parse_smbios1($2);
5747 $smbios1->{uuid} = $uuid_str;
5748 print $outfd $1.print_smbios1($smbios1)."\n";
91bd6c90
DM
5749 } else {
5750 print $outfd $line;
5751 }
5752}
5753
5754sub scan_volids {
5755 my ($cfg, $vmid) = @_;
5756
5757 my $info = PVE::Storage::vdisk_list($cfg, undef, $vmid);
5758
5759 my $volid_hash = {};
5760 foreach my $storeid (keys %$info) {
5761 foreach my $item (@{$info->{$storeid}}) {
5762 next if !($item->{volid} && $item->{size});
5996a936 5763 $item->{path} = PVE::Storage::path($cfg, $item->{volid});
91bd6c90
DM
5764 $volid_hash->{$item->{volid}} = $item;
5765 }
5766 }
5767
5768 return $volid_hash;
5769}
5770
77019edf
WB
5771sub is_volume_in_use {
5772 my ($storecfg, $conf, $skip_drive, $volid) = @_;
a8e2f942 5773
77019edf 5774 my $path = PVE::Storage::path($storecfg, $volid);
a8e2f942
DM
5775
5776 my $scan_config = sub {
5777 my ($cref, $snapname) = @_;
5778
5779 foreach my $key (keys %$cref) {
5780 my $value = $cref->{$key};
74479ee9 5781 if (is_valid_drivename($key)) {
a8e2f942
DM
5782 next if $skip_drive && $key eq $skip_drive;
5783 my $drive = parse_drive($key, $value);
5784 next if !$drive || !$drive->{file} || drive_is_cdrom($drive);
77019edf 5785 return 1 if $volid eq $drive->{file};
a8e2f942 5786 if ($drive->{file} =~ m!^/!) {
77019edf 5787 return 1 if $drive->{file} eq $path;
a8e2f942
DM
5788 } else {
5789 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file}, 1);
5790 next if !$storeid;
5791 my $scfg = PVE::Storage::storage_config($storecfg, $storeid, 1);
5792 next if !$scfg;
77019edf 5793 return 1 if $path eq PVE::Storage::path($storecfg, $drive->{file}, $snapname);
a8e2f942
DM
5794 }
5795 }
5796 }
77019edf
WB
5797
5798 return 0;
a8e2f942
DM
5799 };
5800
77019edf 5801 return 1 if &$scan_config($conf);
a8e2f942
DM
5802
5803 undef $skip_drive;
5804
77019edf
WB
5805 foreach my $snapname (keys %{$conf->{snapshots}}) {
5806 return 1 if &$scan_config($conf->{snapshots}->{$snapname}, $snapname);
a8e2f942
DM
5807 }
5808
77019edf 5809 return 0;
a8e2f942
DM
5810}
5811
91bd6c90
DM
5812sub update_disksize {
5813 my ($vmid, $conf, $volid_hash) = @_;
be190583 5814
91bd6c90 5815 my $changes;
53b81297 5816 my $prefix = "VM $vmid:";
91bd6c90 5817
c449137a
DC
5818 # used and unused disks
5819 my $referenced = {};
91bd6c90 5820
5996a936
DM
5821 # Note: it is allowed to define multiple storages with same path (alias), so
5822 # we need to check both 'volid' and real 'path' (two different volid can point
5823 # to the same path).
5824
c449137a 5825 my $referencedpath = {};
be190583 5826
91bd6c90
DM
5827 # update size info
5828 foreach my $opt (keys %$conf) {
74479ee9 5829 if (is_valid_drivename($opt)) {
ed221350 5830 my $drive = parse_drive($opt, $conf->{$opt});
91bd6c90
DM
5831 my $volid = $drive->{file};
5832 next if !$volid;
5833
c449137a 5834 $referenced->{$volid} = 1;
be190583 5835 if ($volid_hash->{$volid} &&
5996a936 5836 (my $path = $volid_hash->{$volid}->{path})) {
c449137a 5837 $referencedpath->{$path} = 1;
5996a936 5838 }
91bd6c90 5839
ed221350 5840 next if drive_is_cdrom($drive);
91bd6c90
DM
5841 next if !$volid_hash->{$volid};
5842
5843 $drive->{size} = $volid_hash->{$volid}->{size};
7a907ce6
DM
5844 my $new = print_drive($vmid, $drive);
5845 if ($new ne $conf->{$opt}) {
5846 $changes = 1;
5847 $conf->{$opt} = $new;
53b81297 5848 print "$prefix update disk '$opt' information.\n";
7a907ce6 5849 }
91bd6c90
DM
5850 }
5851 }
5852
5996a936
DM
5853 # remove 'unusedX' entry if volume is used
5854 foreach my $opt (keys %$conf) {
5855 next if $opt !~ m/^unused\d+$/;
5856 my $volid = $conf->{$opt};
5857 my $path = $volid_hash->{$volid}->{path} if $volid_hash->{$volid};
c449137a 5858 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
53b81297 5859 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5996a936
DM
5860 $changes = 1;
5861 delete $conf->{$opt};
5862 }
c449137a
DC
5863
5864 $referenced->{$volid} = 1;
5865 $referencedpath->{$path} = 1 if $path;
5996a936
DM
5866 }
5867
91bd6c90
DM
5868 foreach my $volid (sort keys %$volid_hash) {
5869 next if $volid =~ m/vm-$vmid-state-/;
c449137a 5870 next if $referenced->{$volid};
5996a936
DM
5871 my $path = $volid_hash->{$volid}->{path};
5872 next if !$path; # just to be sure
c449137a 5873 next if $referencedpath->{$path};
91bd6c90 5874 $changes = 1;
53b81297
TL
5875 my $key = PVE::QemuConfig->add_unused_volume($conf, $volid);
5876 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
c449137a 5877 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
91bd6c90
DM
5878 }
5879
5880 return $changes;
5881}
5882
5883sub rescan {
9224dcee 5884 my ($vmid, $nolock, $dryrun) = @_;
91bd6c90 5885
20519efc 5886 my $cfg = PVE::Storage::config();
91bd6c90 5887
b9a1a3ab
TL
5888 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5889 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
4771526a
AA
5890 foreach my $stor (keys %{$cfg->{ids}}) {
5891 delete($cfg->{ids}->{$stor}) if ! $cfg->{ids}->{$stor}->{content}->{images};
5892 }
5893
53b81297 5894 print "rescan volumes...\n";
91bd6c90
DM
5895 my $volid_hash = scan_volids($cfg, $vmid);
5896
5897 my $updatefn = sub {
5898 my ($vmid) = @_;
5899
ffda963f 5900 my $conf = PVE::QemuConfig->load_config($vmid);
be190583 5901
ffda963f 5902 PVE::QemuConfig->check_lock($conf);
91bd6c90 5903
03da3f0d
DM
5904 my $vm_volids = {};
5905 foreach my $volid (keys %$volid_hash) {
5906 my $info = $volid_hash->{$volid};
5907 $vm_volids->{$volid} = $info if $info->{vmid} && $info->{vmid} == $vmid;
5908 }
5909
5910 my $changes = update_disksize($vmid, $conf, $vm_volids);
91bd6c90 5911
9224dcee 5912 PVE::QemuConfig->write_config($vmid, $conf) if $changes && !$dryrun;
91bd6c90
DM
5913 };
5914
5915 if (defined($vmid)) {
5916 if ($nolock) {
5917 &$updatefn($vmid);
5918 } else {
ffda963f 5919 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
91bd6c90
DM
5920 }
5921 } else {
5922 my $vmlist = config_list();
5923 foreach my $vmid (keys %$vmlist) {
5924 if ($nolock) {
5925 &$updatefn($vmid);
5926 } else {
ffda963f 5927 PVE::QemuConfig->lock_config($vmid, $updatefn, $vmid);
be190583 5928 }
91bd6c90
DM
5929 }
5930 }
5931}
5932
5933sub restore_vma_archive {
5934 my ($archive, $vmid, $user, $opts, $comp) = @_;
5935
91bd6c90
DM
5936 my $readfrom = $archive;
5937
7c536e11
WB
5938 my $cfg = PVE::Storage::config();
5939 my $commands = [];
5940 my $bwlimit = $opts->{bwlimit};
5941
5942 my $dbg_cmdstring = '';
5943 my $add_pipe = sub {
5944 my ($cmd) = @_;
5945 push @$commands, $cmd;
5946 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5947 $dbg_cmdstring .= PVE::Tools::cmd2string($cmd);
91bd6c90 5948 $readfrom = '-';
7c536e11
WB
5949 };
5950
5951 my $input = undef;
5952 if ($archive eq '-') {
5953 $input = '<&STDIN';
5954 } else {
5955 # If we use a backup from a PVE defined storage we also consider that
5956 # storage's rate limit:
5957 my (undef, $volid) = PVE::Storage::path_to_volume_id($cfg, $archive);
5958 if (defined($volid)) {
5959 my ($sid, undef) = PVE::Storage::parse_volume_id($volid);
5960 my $readlimit = PVE::Storage::get_bandwidth_limit('restore', [$sid], $bwlimit);
5961 if ($readlimit) {
5962 print STDERR "applying read rate limit: $readlimit\n";
9444c6e4 5963 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
7c536e11
WB
5964 $add_pipe->($cstream);
5965 }
5966 }
5967 }
5968
5969 if ($comp) {
5970 my $cmd;
91bd6c90 5971 if ($comp eq 'gzip') {
7c536e11 5972 $cmd = ['zcat', $readfrom];
91bd6c90 5973 } elsif ($comp eq 'lzop') {
7c536e11 5974 $cmd = ['lzop', '-d', '-c', $readfrom];
91bd6c90
DM
5975 } else {
5976 die "unknown compression method '$comp'\n";
5977 }
7c536e11 5978 $add_pipe->($cmd);
91bd6c90
DM
5979 }
5980
5981 my $tmpdir = "/var/tmp/vzdumptmp$$";
5982 rmtree $tmpdir;
5983
5984 # disable interrupts (always do cleanups)
5b97ef24
TL
5985 local $SIG{INT} =
5986 local $SIG{TERM} =
5987 local $SIG{QUIT} =
5988 local $SIG{HUP} = sub { warn "got interrupt - ignored\n"; };
91bd6c90
DM
5989
5990 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5991 POSIX::mkfifo($mapfifo, 0600);
5992 my $fifofh;
5993
5994 my $openfifo = sub {
5995 open($fifofh, '>', $mapfifo) || die $!;
5996 };
5997
7c536e11 5998 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
91bd6c90
DM
5999
6000 my $oldtimeout;
6001 my $timeout = 5;
6002
6003 my $devinfo = {};
6004
6005 my $rpcenv = PVE::RPCEnvironment::get();
6006
ffda963f 6007 my $conffile = PVE::QemuConfig->config_file($vmid);
91bd6c90
DM
6008 my $tmpfn = "$conffile.$$.tmp";
6009
ed221350 6010 # Note: $oldconf is undef if VM does not exists
ffda963f
FG
6011 my $cfs_path = PVE::QemuConfig->cfs_config_path($vmid);
6012 my $oldconf = PVE::Cluster::cfs_read_file($cfs_path);
ed221350 6013
7c536e11
WB
6014 my %storage_limits;
6015
91bd6c90
DM
6016 my $print_devmap = sub {
6017 my $virtdev_hash = {};
6018
6019 my $cfgfn = "$tmpdir/qemu-server.conf";
6020
6021 # we can read the config - that is already extracted
6022 my $fh = IO::File->new($cfgfn, "r") ||
6023 "unable to read qemu-server.conf - $!\n";
6024
6738ab9c 6025 my $fwcfgfn = "$tmpdir/qemu-server.fw";
3457d090
WL
6026 if (-f $fwcfgfn) {
6027 my $pve_firewall_dir = '/etc/pve/firewall';
6028 mkdir $pve_firewall_dir; # make sure the dir exists
6029 PVE::Tools::file_copy($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6030 }
6738ab9c 6031
91bd6c90
DM
6032 while (defined(my $line = <$fh>)) {
6033 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6034 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6035 die "archive does not contain data for drive '$virtdev'\n"
6036 if !$devinfo->{$devname};
6037 if (defined($opts->{storage})) {
6038 $storeid = $opts->{storage} || 'local';
6039 } elsif (!$storeid) {
6040 $storeid = 'local';
6041 }
6042 $format = 'raw' if !$format;
6043 $devinfo->{$devname}->{devname} = $devname;
6044 $devinfo->{$devname}->{virtdev} = $virtdev;
6045 $devinfo->{$devname}->{format} = $format;
6046 $devinfo->{$devname}->{storeid} = $storeid;
6047
be190583 6048 # check permission on storage
91bd6c90
DM
6049 my $pool = $opts->{pool}; # todo: do we need that?
6050 if ($user ne 'root@pam') {
6051 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6052 }
6053
7c536e11
WB
6054 $storage_limits{$storeid} = $bwlimit;
6055
91bd6c90
DM
6056 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6057 }
6058 }
6059
7c536e11
WB
6060 foreach my $key (keys %storage_limits) {
6061 my $limit = PVE::Storage::get_bandwidth_limit('restore', [$key], $bwlimit);
6062 next if !$limit;
6063 print STDERR "rate limit for storage $key: $limit KiB/s\n";
6064 $storage_limits{$key} = $limit * 1024;
6065 }
6066
91bd6c90 6067 foreach my $devname (keys %$devinfo) {
be190583
DM
6068 die "found no device mapping information for device '$devname'\n"
6069 if !$devinfo->{$devname}->{virtdev};
91bd6c90
DM
6070 }
6071
ed221350 6072 # create empty/temp config
be190583 6073 if ($oldconf) {
ed221350
DM
6074 PVE::Tools::file_set_contents($conffile, "memory: 128\n");
6075 foreach_drive($oldconf, sub {
6076 my ($ds, $drive) = @_;
6077
6078 return if drive_is_cdrom($drive);
6079
6080 my $volid = $drive->{file};
6081
6082 return if !$volid || $volid =~ m|^/|;
6083
6084 my ($path, $owner) = PVE::Storage::path($cfg, $volid);
6085 return if !$path || !$owner || ($owner != $vmid);
6086
6087 # Note: only delete disk we want to restore
6088 # other volumes will become unused
6089 if ($virtdev_hash->{$ds}) {
6b72854b
FG
6090 eval { PVE::Storage::vdisk_free($cfg, $volid); };
6091 if (my $err = $@) {
6092 warn $err;
6093 }
ed221350
DM
6094 }
6095 });
381b8fae
DC
6096
6097 # delete vmstate files
6098 # since after the restore we have no snapshots anymore
6099 foreach my $snapname (keys %{$oldconf->{snapshots}}) {
6100 my $snap = $oldconf->{snapshots}->{$snapname};
6101 if ($snap->{vmstate}) {
6102 eval { PVE::Storage::vdisk_free($cfg, $snap->{vmstate}); };
6103 if (my $err = $@) {
6104 warn $err;
6105 }
6106 }
6107 }
ed221350
DM
6108 }
6109
6110 my $map = {};
91bd6c90
DM
6111 foreach my $virtdev (sort keys %$virtdev_hash) {
6112 my $d = $virtdev_hash->{$virtdev};
6113 my $alloc_size = int(($d->{size} + 1024 - 1)/1024);
7c536e11
WB
6114 my $storeid = $d->{storeid};
6115 my $scfg = PVE::Storage::storage_config($cfg, $storeid);
6116
6117 my $map_opts = '';
6118 if (my $limit = $storage_limits{$storeid}) {
6119 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6120 }
8fd57431
DM
6121
6122 # test if requested format is supported
7c536e11 6123 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($cfg, $storeid);
8fd57431
DM
6124 my $supported = grep { $_ eq $d->{format} } @$validFormats;
6125 $d->{format} = $defFormat if !$supported;
6126
7c536e11 6127 my $volid = PVE::Storage::vdisk_alloc($cfg, $storeid, $vmid,
91bd6c90
DM
6128 $d->{format}, undef, $alloc_size);
6129 print STDERR "new volume ID is '$volid'\n";
6130 $d->{volid} = $volid;
6131 my $path = PVE::Storage::path($cfg, $volid);
6132
5f96f4df
WL
6133 PVE::Storage::activate_volumes($cfg,[$volid]);
6134
91bd6c90 6135 my $write_zeros = 1;
88240a83 6136 if (PVE::Storage::volume_has_feature($cfg, 'sparseinit', $volid)) {
91bd6c90
DM
6137 $write_zeros = 0;
6138 }
6139
7c536e11 6140 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
91bd6c90
DM
6141
6142 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6143 $map->{$virtdev} = $volid;
6144 }
6145
6146 $fh->seek(0, 0) || die "seek failed - $!\n";
6147
6148 my $outfd = new IO::File ($tmpfn, "w") ||
6149 die "unable to write config for VM $vmid\n";
6150
6151 my $cookie = { netcount => 0 };
6152 while (defined(my $line = <$fh>)) {
be190583 6153 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
91bd6c90
DM
6154 }
6155
6156 $fh->close();
6157 $outfd->close();
6158 };
6159
6160 eval {
6161 # enable interrupts
6cb0144a
EK
6162 local $SIG{INT} =
6163 local $SIG{TERM} =
6164 local $SIG{QUIT} =
6165 local $SIG{HUP} =
6166 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
91bd6c90
DM
6167 local $SIG{ALRM} = sub { die "got timeout\n"; };
6168
6169 $oldtimeout = alarm($timeout);
6170
6171 my $parser = sub {
6172 my $line = shift;
6173
6174 print "$line\n";
6175
6176 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6177 my ($dev_id, $size, $devname) = ($1, $2, $3);
6178 $devinfo->{$devname} = { size => $size, dev_id => $dev_id };
6179 } elsif ($line =~ m/^CTIME: /) {
46f58b5f 6180 # we correctly received the vma config, so we can disable
3cf90d7a
DM
6181 # the timeout now for disk allocation (set to 10 minutes, so
6182 # that we always timeout if something goes wrong)
6183 alarm(600);
91bd6c90
DM
6184 &$print_devmap();
6185 print $fifofh "done\n";
6186 my $tmp = $oldtimeout || 0;
6187 $oldtimeout = undef;
6188 alarm($tmp);
6189 close($fifofh);
6190 }
6191 };
be190583 6192
7c536e11
WB
6193 print "restore vma archive: $dbg_cmdstring\n";
6194 run_command($commands, input => $input, outfunc => $parser, afterfork => $openfifo);
91bd6c90
DM
6195 };
6196 my $err = $@;
6197
6198 alarm($oldtimeout) if $oldtimeout;
6199
5f96f4df
WL
6200 my $vollist = [];
6201 foreach my $devname (keys %$devinfo) {
6202 my $volid = $devinfo->{$devname}->{volid};
6203 push @$vollist, $volid if $volid;
6204 }
6205
5f96f4df
WL
6206 PVE::Storage::deactivate_volumes($cfg, $vollist);
6207
91bd6c90
DM
6208 unlink $mapfifo;
6209
6210 if ($err) {
6211 rmtree $tmpdir;
6212 unlink $tmpfn;
6213
91bd6c90
DM
6214 foreach my $devname (keys %$devinfo) {
6215 my $volid = $devinfo->{$devname}->{volid};
6216 next if !$volid;
6217 eval {
6218 if ($volid =~ m|^/|) {
6219 unlink $volid || die 'unlink failed\n';
6220 } else {
6221 PVE::Storage::vdisk_free($cfg, $volid);
6222 }
6223 print STDERR "temporary volume '$volid' sucessfuly removed\n";
6224 };
6225 print STDERR "unable to cleanup '$volid' - $@" if $@;
6226 }
6227 die $err;
6228 }
6229
6230 rmtree $tmpdir;
ed221350
DM
6231
6232 rename($tmpfn, $conffile) ||
91bd6c90
DM
6233 die "unable to commit configuration file '$conffile'\n";
6234
ed221350
DM
6235 PVE::Cluster::cfs_update(); # make sure we read new file
6236
91bd6c90
DM
6237 eval { rescan($vmid, 1); };
6238 warn $@ if $@;
6239}
6240
6241sub restore_tar_archive {
6242 my ($archive, $vmid, $user, $opts) = @_;
6243
9c502e26 6244 if ($archive ne '-') {
ed221350 6245 my $firstfile = tar_archive_read_firstfile($archive);
9c502e26
DM
6246 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6247 if $firstfile ne 'qemu-server.conf';
6248 }
3e16d5fc 6249
20519efc 6250 my $storecfg = PVE::Storage::config();
ebb55558 6251
ed221350 6252 # destroy existing data - keep empty config
ffda963f 6253 my $vmcfgfn = PVE::QemuConfig->config_file($vmid);
ebb55558 6254 destroy_vm($storecfg, $vmid, 1) if -f $vmcfgfn;
ed221350 6255
3e16d5fc
DM
6256 my $tocmd = "/usr/lib/qemu-server/qmextract";
6257
2415a446 6258 $tocmd .= " --storage " . PVE::Tools::shellquote($opts->{storage}) if $opts->{storage};
a0d1b1a2 6259 $tocmd .= " --pool " . PVE::Tools::shellquote($opts->{pool}) if $opts->{pool};
3e16d5fc
DM
6260 $tocmd .= ' --prealloc' if $opts->{prealloc};
6261 $tocmd .= ' --info' if $opts->{info};
6262
a0d1b1a2 6263 # tar option "xf" does not autodetect compression when read from STDIN,
9c502e26 6264 # so we pipe to zcat
2415a446
DM
6265 my $cmd = "zcat -f|tar xf " . PVE::Tools::shellquote($archive) . " " .
6266 PVE::Tools::shellquote("--to-command=$tocmd");
3e16d5fc
DM
6267
6268 my $tmpdir = "/var/tmp/vzdumptmp$$";
6269 mkpath $tmpdir;
6270
6271 local $ENV{VZDUMP_TMPDIR} = $tmpdir;
6272 local $ENV{VZDUMP_VMID} = $vmid;
a0d1b1a2 6273 local $ENV{VZDUMP_USER} = $user;
3e16d5fc 6274
ffda963f 6275 my $conffile = PVE::QemuConfig->config_file($vmid);
3e16d5fc
DM
6276 my $tmpfn = "$conffile.$$.tmp";
6277
6278 # disable interrupts (always do cleanups)
6cb0144a
EK
6279 local $SIG{INT} =
6280 local $SIG{TERM} =
6281 local $SIG{QUIT} =
6282 local $SIG{HUP} = sub { print STDERR "got interrupt - ignored\n"; };
3e16d5fc 6283
afdb31d5 6284 eval {
3e16d5fc 6285 # enable interrupts
6cb0144a
EK
6286 local $SIG{INT} =
6287 local $SIG{TERM} =
6288 local $SIG{QUIT} =
6289 local $SIG{HUP} =
6290 local $SIG{PIPE} = sub { die "interrupted by signal\n"; };
3e16d5fc 6291
9c502e26
DM
6292 if ($archive eq '-') {
6293 print "extracting archive from STDIN\n";
6294 run_command($cmd, input => "<&STDIN");
6295 } else {
6296 print "extracting archive '$archive'\n";
6297 run_command($cmd);
6298 }
3e16d5fc
DM
6299
6300 return if $opts->{info};
6301
6302 # read new mapping
6303 my $map = {};
6304 my $statfile = "$tmpdir/qmrestore.stat";
6305 if (my $fd = IO::File->new($statfile, "r")) {
6306 while (defined (my $line = <$fd>)) {
6307 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6308 $map->{$1} = $2 if $1;
6309 } else {
6310 print STDERR "unable to parse line in statfile - $line\n";
6311 }
6312 }
6313 $fd->close();
6314 }
6315
6316 my $confsrc = "$tmpdir/qemu-server.conf";
6317
6318 my $srcfd = new IO::File($confsrc, "r") ||
6319 die "unable to open file '$confsrc'\n";
6320
6321 my $outfd = new IO::File ($tmpfn, "w") ||
6322 die "unable to write config for VM $vmid\n";
6323
91bd6c90 6324 my $cookie = { netcount => 0 };
3e16d5fc 6325 while (defined (my $line = <$srcfd>)) {
be190583 6326 restore_update_config_line($outfd, $cookie, $vmid, $map, $line, $opts->{unique});
3e16d5fc
DM
6327 }
6328
6329 $srcfd->close();
6330 $outfd->close();
6331 };
6332 my $err = $@;
6333
afdb31d5 6334 if ($err) {
3e16d5fc
DM
6335
6336 unlink $tmpfn;
6337
ed221350 6338 tar_restore_cleanup($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info};
afdb31d5 6339
3e16d5fc 6340 die $err;
afdb31d5 6341 }
3e16d5fc
DM
6342
6343 rmtree $tmpdir;
6344
6345 rename $tmpfn, $conffile ||
6346 die "unable to commit configuration file '$conffile'\n";
91bd6c90 6347
ed221350
DM
6348 PVE::Cluster::cfs_update(); # make sure we read new file
6349
91bd6c90
DM
6350 eval { rescan($vmid, 1); };
6351 warn $@ if $@;
3e16d5fc
DM
6352};
6353
65a5ce88 6354sub foreach_storage_used_by_vm {
18bfb361
DM
6355 my ($conf, $func) = @_;
6356
6357 my $sidhash = {};
6358
8ddbcf8b
FG
6359 foreach_drive($conf, sub {
6360 my ($ds, $drive) = @_;
6361 return if drive_is_cdrom($drive);
18bfb361
DM
6362
6363 my $volid = $drive->{file};
6364
6365 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
be190583 6366 $sidhash->{$sid} = $sid if $sid;
8ddbcf8b 6367 });
18bfb361
DM
6368
6369 foreach my $sid (sort keys %$sidhash) {
6370 &$func($sid);
6371 }
6372}
6373
e5eaa028
WL
6374sub do_snapshots_with_qemu {
6375 my ($storecfg, $volid) = @_;
6376
6377 my $storage_name = PVE::Storage::parse_volume_id($volid);
6378
116da784
WL
6379 if ($qemu_snap_storage->{$storecfg->{ids}->{$storage_name}->{type}}
6380 && !$storecfg->{ids}->{$storage_name}->{krbd}){
e5eaa028
WL
6381 return 1;
6382 }
6383
6384 if ($volid =~ m/\.(qcow2|qed)$/){
6385 return 1;
6386 }
6387
6388 return undef;
6389}
6390
4dcc780c 6391sub qga_check_running {
a4938c72 6392 my ($vmid, $nowarn) = @_;
4dcc780c
WL
6393
6394 eval { vm_mon_cmd($vmid, "guest-ping", timeout => 3); };
6395 if ($@) {
a4938c72 6396 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
4dcc780c
WL
6397 return 0;
6398 }
6399 return 1;
6400}
6401
04a69bb4
AD
6402sub template_create {
6403 my ($vmid, $conf, $disk) = @_;
6404
04a69bb4 6405 my $storecfg = PVE::Storage::config();
04a69bb4 6406
9cd07842
DM
6407 foreach_drive($conf, sub {
6408 my ($ds, $drive) = @_;
6409
6410 return if drive_is_cdrom($drive);
6411 return if $disk && $ds ne $disk;
6412
6413 my $volid = $drive->{file};
bbd56097 6414 return if !PVE::Storage::volume_has_feature($storecfg, 'template', $volid);
9cd07842 6415
04a69bb4
AD
6416 my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
6417 $drive->{file} = $voliddst;
152fe752 6418 $conf->{$ds} = print_drive($vmid, $drive);
ffda963f 6419 PVE::QemuConfig->write_config($vmid, $conf);
04a69bb4 6420 });
04a69bb4
AD
6421}
6422
5133de42 6423sub qemu_img_convert {
988e2714 6424 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5133de42
AD
6425
6426 my $storecfg = PVE::Storage::config();
6427 my ($src_storeid, $src_volname) = PVE::Storage::parse_volume_id($src_volid, 1);
6428 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid, 1);
6429
6430 if ($src_storeid && $dst_storeid) {
6bb91c17
DM
6431
6432 PVE::Storage::activate_volumes($storecfg, [$src_volid], $snapname);
6433
5133de42
AD
6434 my $src_scfg = PVE::Storage::storage_config($storecfg, $src_storeid);
6435 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
6436
6437 my $src_format = qemu_img_format($src_scfg, $src_volname);
6438 my $dst_format = qemu_img_format($dst_scfg, $dst_volname);
6439
6440 my $src_path = PVE::Storage::path($storecfg, $src_volid, $snapname);
6441 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
6442
6443 my $cmd = [];
eed24303 6444 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
29004a20 6445 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
d4940091
FG
6446 push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
6447 push @$cmd, '-T', 'none' if $src_scfg->{type} eq 'zfspool';
988e2714
WB
6448 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6449 if ($is_zero_initialized) {
6450 push @$cmd, "zeroinit:$dst_path";
6451 } else {
6452 push @$cmd, $dst_path;
6453 }
5133de42
AD
6454
6455 my $parser = sub {
6456 my $line = shift;
6457 if($line =~ m/\((\S+)\/100\%\)/){
6458 my $percent = $1;
6459 my $transferred = int($size * $percent / 100);
6460 my $remaining = $size - $transferred;
6461
6462 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6463 }
6464
6465 };
6466
6467 eval { run_command($cmd, timeout => undef, outfunc => $parser); };
6468 my $err = $@;
6469 die "copy failed: $err" if $err;
6470 }
6471}
6472
6473sub qemu_img_format {
6474 my ($scfg, $volname) = @_;
6475
9c52f5ed 6476 if ($scfg->{path} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
5133de42 6477 return $1;
be190583 6478 } else {
5133de42 6479 return "raw";
5133de42
AD
6480 }
6481}
6482
cfad42af 6483sub qemu_drive_mirror {
5619e74a 6484 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
cfad42af 6485
5a345967
AD
6486 $jobs = {} if !$jobs;
6487
6488 my $qemu_target;
6489 my $format;
35e4ab04 6490 $jobs->{"drive-$drive"} = {};
152fe752 6491
1e5143de 6492 if ($dst_volid =~ /^nbd:/) {
87955688 6493 $qemu_target = $dst_volid;
5a345967 6494 $format = "nbd";
5a345967 6495 } else {
5a345967
AD
6496 my $storecfg = PVE::Storage::config();
6497 my ($dst_storeid, $dst_volname) = PVE::Storage::parse_volume_id($dst_volid);
6498
6499 my $dst_scfg = PVE::Storage::storage_config($storecfg, $dst_storeid);
cfad42af 6500
5a345967 6501 $format = qemu_img_format($dst_scfg, $dst_volname);
21ccdb50 6502
5a345967 6503 my $dst_path = PVE::Storage::path($storecfg, $dst_volid);
21ccdb50 6504
5a345967
AD
6505 $qemu_target = $is_zero_initialized ? "zeroinit:$dst_path" : $dst_path;
6506 }
988e2714
WB
6507
6508 my $opts = { timeout => 10, device => "drive-$drive", mode => "existing", sync => "full", target => $qemu_target };
88383920
DM
6509 $opts->{format} = $format if $format;
6510
5a345967 6511 print "drive mirror is starting for drive-$drive\n";
21ccdb50 6512
5a345967 6513 eval { vm_mon_cmd($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
35e4ab04 6514
5a345967
AD
6515 if (my $err = $@) {
6516 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
6517 die "mirroring error: $err";
6518 }
6519
5619e74a 6520 qemu_drive_mirror_monitor ($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
5a345967
AD
6521}
6522
6523sub qemu_drive_mirror_monitor {
5619e74a 6524 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
2e953867 6525
08ac653f 6526 eval {
5a345967
AD
6527 my $err_complete = 0;
6528
08ac653f 6529 while (1) {
5a345967
AD
6530 die "storage migration timed out\n" if $err_complete > 300;
6531
08ac653f 6532 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
08ac653f 6533
5a345967
AD
6534 my $running_mirror_jobs = {};
6535 foreach my $stat (@$stats) {
6536 next if $stat->{type} ne 'mirror';
6537 $running_mirror_jobs->{$stat->{device}} = $stat;
6538 }
08ac653f 6539
5a345967 6540 my $readycounter = 0;
67fb9de6 6541
5a345967
AD
6542 foreach my $job (keys %$jobs) {
6543
6544 if(defined($jobs->{$job}->{complete}) && !defined($running_mirror_jobs->{$job})) {
6545 print "$job : finished\n";
6546 delete $jobs->{$job};
6547 next;
6548 }
6549
bd2d5fe6 6550 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
f34ebd52 6551
5a345967
AD
6552 my $busy = $running_mirror_jobs->{$job}->{busy};
6553 my $ready = $running_mirror_jobs->{$job}->{ready};
6554 if (my $total = $running_mirror_jobs->{$job}->{len}) {
6555 my $transferred = $running_mirror_jobs->{$job}->{offset} || 0;
6556 my $remaining = $total - $transferred;
6557 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
08ac653f 6558
5a345967
AD
6559 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6560 }
f34ebd52 6561
d1782eba 6562 $readycounter++ if $running_mirror_jobs->{$job}->{ready};
5a345967 6563 }
b467f79a 6564
5a345967
AD
6565 last if scalar(keys %$jobs) == 0;
6566
6567 if ($readycounter == scalar(keys %$jobs)) {
6568 print "all mirroring jobs are ready \n";
6569 last if $skipcomplete; #do the complete later
6570
6571 if ($vmiddst && $vmiddst != $vmid) {
1a988fd2
DC
6572 my $agent_running = $qga && qga_check_running($vmid);
6573 if ($agent_running) {
5619e74a
AD
6574 print "freeze filesystem\n";
6575 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-freeze"); };
6576 } else {
6577 print "suspend vm\n";
6578 eval { PVE::QemuServer::vm_suspend($vmid, 1); };
6579 }
6580
5a345967
AD
6581 # if we clone a disk for a new target vm, we don't switch the disk
6582 PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs);
5619e74a 6583
1a988fd2 6584 if ($agent_running) {
5619e74a
AD
6585 print "unfreeze filesystem\n";
6586 eval { PVE::QemuServer::vm_mon_cmd($vmid, "guest-fsfreeze-thaw"); };
6587 } else {
6588 print "resume vm\n";
6589 eval { PVE::QemuServer::vm_resume($vmid, 1, 1); };
6590 }
6591
2e953867 6592 last;
5a345967
AD
6593 } else {
6594
6595 foreach my $job (keys %$jobs) {
6596 # try to switch the disk if source and destination are on the same guest
bd2d5fe6 6597 print "$job: Completing block job...\n";
5a345967
AD
6598
6599 eval { vm_mon_cmd($vmid, "block-job-complete", device => $job) };
6600 if ($@ =~ m/cannot be completed/) {
bd2d5fe6 6601 print "$job: Block job cannot be completed, try again.\n";
5a345967
AD
6602 $err_complete++;
6603 }else {
bd2d5fe6 6604 print "$job: Completed successfully.\n";
5a345967
AD
6605 $jobs->{$job}->{complete} = 1;
6606 }
6607 }
2e953867 6608 }
08ac653f 6609 }
08ac653f 6610 sleep 1;
cfad42af 6611 }
08ac653f 6612 };
88383920 6613 my $err = $@;
08ac653f 6614
88383920 6615 if ($err) {
5a345967 6616 eval { PVE::QemuServer::qemu_blockjobs_cancel($vmid, $jobs) };
88383920
DM
6617 die "mirroring error: $err";
6618 }
6619
5a345967
AD
6620}
6621
6622sub qemu_blockjobs_cancel {
6623 my ($vmid, $jobs) = @_;
6624
6625 foreach my $job (keys %$jobs) {
bd2d5fe6 6626 print "$job: Cancelling block job\n";
5a345967
AD
6627 eval { vm_mon_cmd($vmid, "block-job-cancel", device => $job); };
6628 $jobs->{$job}->{cancel} = 1;
6629 }
6630
6631 while (1) {
6632 my $stats = vm_mon_cmd($vmid, "query-block-jobs");
6633
6634 my $running_jobs = {};
6635 foreach my $stat (@$stats) {
6636 $running_jobs->{$stat->{device}} = $stat;
6637 }
6638
6639 foreach my $job (keys %$jobs) {
6640
bd2d5fe6
WB
6641 if (defined($jobs->{$job}->{cancel}) && !defined($running_jobs->{$job})) {
6642 print "$job: Done.\n";
5a345967
AD
6643 delete $jobs->{$job};
6644 }
6645 }
6646
6647 last if scalar(keys %$jobs) == 0;
6648
6649 sleep 1;
cfad42af
AD
6650 }
6651}
6652
152fe752 6653sub clone_disk {
be190583 6654 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
5619e74a 6655 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
152fe752
DM
6656
6657 my $newvolid;
6658
6659 if (!$full) {
6660 print "create linked clone of drive $drivename ($drive->{file})\n";
258e646c 6661 $newvolid = PVE::Storage::vdisk_clone($storecfg, $drive->{file}, $newvmid, $snapname);
152fe752
DM
6662 push @$newvollist, $newvolid;
6663 } else {
5a345967 6664
152fe752
DM
6665 my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
6666 $storeid = $storage if $storage;
6667
44549149 6668 my $dst_format = resolve_dst_disk_format($storecfg, $storeid, $volname, $format);
152fe752
DM
6669 my ($size) = PVE::Storage::volume_size_info($storecfg, $drive->{file}, 3);
6670
6671 print "create full clone of drive $drivename ($drive->{file})\n";
931432bd
WB
6672 my $name = undef;
6673 if (drive_is_cloudinit($drive)) {
6674 $name = "vm-$newvmid-cloudinit";
8fa6a851 6675 $snapname = undef;
931432bd
WB
6676 # cloudinit only supports raw and qcow2 atm:
6677 if ($dst_format eq 'qcow2') {
6678 $name .= '.qcow2';
6679 } elsif ($dst_format ne 'raw') {
6680 die "clone: unhandled format for cloudinit image\n";
6681 }
6682 }
6683 $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
152fe752
DM
6684 push @$newvollist, $newvolid;
6685
3999f370 6686 PVE::Storage::activate_volumes($storecfg, [$newvolid]);
1dbd6d30 6687
988e2714 6688 my $sparseinit = PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $newvolid);
152fe752 6689 if (!$running || $snapname) {
988e2714 6690 qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
152fe752 6691 } else {
2e541679
AD
6692
6693 my $kvmver = get_running_qemu_version ($vmid);
6694 if (!qemu_machine_feature_enabled (undef, $kvmver, 2, 7)) {
961af8a3
WB
6695 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6696 if $drive->{iothread};
2e541679 6697 }
2af848a2 6698
5619e74a 6699 qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
be190583 6700 }
152fe752
DM
6701 }
6702
6703 my ($size) = PVE::Storage::volume_size_info($storecfg, $newvolid, 3);
6704
6705 my $disk = $drive;
6706 $disk->{format} = undef;
6707 $disk->{file} = $newvolid;
6708 $disk->{size} = $size;
6709
6710 return $disk;
6711}
6712
ff556cf2
DM
6713# this only works if VM is running
6714sub get_current_qemu_machine {
6715 my ($vmid) = @_;
6716
6717 my $cmd = { execute => 'query-machines', arguments => {} };
8e90138a 6718 my $res = vm_qmp_command($vmid, $cmd);
ff556cf2
DM
6719
6720 my ($current, $default);
6721 foreach my $e (@$res) {
6722 $default = $e->{name} if $e->{'is-default'};
6723 $current = $e->{name} if $e->{'is-current'};
6724 }
6725
6726 # fallback to the default machine if current is not supported by qemu
6727 return $current || $default || 'pc';
6728}
6729
98cfd8b6
AD
6730sub get_running_qemu_version {
6731 my ($vmid) = @_;
6732 my $cmd = { execute => 'query-version', arguments => {} };
6733 my $res = vm_qmp_command($vmid, $cmd);
6734 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6735}
6736
23f73120
AD
6737sub qemu_machine_feature_enabled {
6738 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6739
6740 my $current_major;
6741 my $current_minor;
6742
d731ecbe 6743 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
23f73120
AD
6744
6745 $current_major = $3;
6746 $current_minor = $4;
6747
6748 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6749
6750 $current_major = $1;
6751 $current_minor = $2;
6752 }
6753
dd84e5ec
WB
6754 return 1 if $current_major > $version_major ||
6755 ($current_major == $version_major &&
6756 $current_minor >= $version_minor);
23f73120
AD
6757}
6758
42dbd2ee
AD
6759sub qemu_machine_pxe {
6760 my ($vmid, $conf, $machine) = @_;
6761
6762 $machine = PVE::QemuServer::get_current_qemu_machine($vmid) if !$machine;
6763
3807f3e4
DC
6764 if ($conf->{machine} && $conf->{machine} =~ m/\.pxe$/) {
6765 $machine .= '.pxe';
42dbd2ee
AD
6766 }
6767
d1363934 6768 return $machine;
42dbd2ee
AD
6769}
6770
249c4a6c
AD
6771sub qemu_use_old_bios_files {
6772 my ($machine_type) = @_;
6773
6774 return if !$machine_type;
6775
6776 my $use_old_bios_files = undef;
6777
6778 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6779 $machine_type = $1;
6780 $use_old_bios_files = 1;
6781 } else {
74cc511f 6782 my $kvmver = kvm_user_version();
249c4a6c
AD
6783 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6784 # load new efi bios files on migration. So this hack is required to allow
6785 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6786 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
74cc511f 6787 $use_old_bios_files = !qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 4);
249c4a6c
AD
6788 }
6789
6790 return ($use_old_bios_files, $machine_type);
6791}
6792
96ed3574
WB
6793sub create_efidisk($$$$$) {
6794 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
3e1f1122 6795
96ed3574
WB
6796 my (undef, $ovmf_vars) = get_ovmf_files($arch);
6797 die "EFI vars default image not found\n" if ! -f $ovmf_vars;
3e1f1122 6798
96ed3574 6799 my $vars_size = PVE::Tools::convert_size(-s $ovmf_vars, 'b' => 'kb');
3e1f1122
TL
6800 my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6801 PVE::Storage::activate_volumes($storecfg, [$volid]);
6802
6803 my $path = PVE::Storage::path($storecfg, $volid);
6804 eval {
96ed3574 6805 run_command(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
3e1f1122
TL
6806 };
6807 die "Copying EFI vars image failed: $@" if $@;
6808
6809 return ($volid, $vars_size);
6810}
6811
22de899a
AD
6812sub vm_iothreads_list {
6813 my ($vmid) = @_;
6814
6815 my $res = vm_mon_cmd($vmid, 'query-iothreads');
6816
6817 my $iothreads = {};
6818 foreach my $iothread (@$res) {
6819 $iothreads->{ $iothread->{id} } = $iothread->{"thread-id"};
6820 }
6821
6822 return $iothreads;
6823}
6824
ee034f5c
AD
6825sub scsihw_infos {
6826 my ($conf, $drive) = @_;
6827
6828 my $maxdev = 0;
6829
7fe1b688 6830 if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)) {
ee034f5c 6831 $maxdev = 7;
a1511b3c 6832 } elsif ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
ee034f5c
AD
6833 $maxdev = 1;
6834 } else {
6835 $maxdev = 256;
6836 }
6837
6838 my $controller = int($drive->{index} / $maxdev);
a1511b3c 6839 my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') ? "virtioscsi" : "scsihw";
ee034f5c
AD
6840
6841 return ($maxdev, $controller, $controller_prefix);
6842}
a1511b3c 6843
075e8249 6844sub add_hyperv_enlightenments {
2894c247 6845 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough, $hv_vendor_id) = @_;
4317f69f 6846
4317f69f
AD
6847 return if $winversion < 6;
6848 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6849
2894c247
DC
6850 if ($gpu_passthrough || defined($hv_vendor_id)) {
6851 $hv_vendor_id //= 'proxmox';
6852 push @$cpuFlags , "hv_vendor_id=$hv_vendor_id";
6853 }
5aba3953 6854
4317f69f
AD
6855 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 3)) {
6856 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6857 push @$cpuFlags , 'hv_vapic';
6858 push @$cpuFlags , 'hv_time';
6859 } else {
6860 push @$cpuFlags , 'hv_spinlocks=0xffff';
6861 }
6862
6863 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 6)) {
6864 push @$cpuFlags , 'hv_reset';
6865 push @$cpuFlags , 'hv_vpindex';
6866 push @$cpuFlags , 'hv_runtime';
6867 }
6868
6869 if ($winversion >= 7) {
6870 push @$cpuFlags , 'hv_relaxed';
ebb346d6 6871
df648a6a 6872 if (qemu_machine_feature_enabled ($machine_type, $kvmver, 2, 12)) {
ebb346d6
AD
6873 push @$cpuFlags , 'hv_synic';
6874 push @$cpuFlags , 'hv_stimer';
6875 }
4317f69f
AD
6876 }
6877}
6878
6879sub windows_version {
6880 my ($ostype) = @_;
6881
6882 return 0 if !$ostype;
6883
6884 my $winversion = 0;
6885
6886 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6887 $winversion = 5;
6888 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6889 $winversion = 6;
6890 } elsif ($ostype =~ m/^win(\d+)$/) {
6891 $winversion = $1;
6892 }
6893
6894 return $winversion;
6895}
6896
44549149
EK
6897sub resolve_dst_disk_format {
6898 my ($storecfg, $storeid, $src_volname, $format) = @_;
6899 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
6900
6901 if (!$format) {
6902 # if no target format is specified, use the source disk format as hint
6903 if ($src_volname) {
6904 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
6905 $format = qemu_img_format($scfg, $src_volname);
6906 } else {
6907 return $defFormat;
6908 }
6909 }
6910
6911 # test if requested format is supported - else use default
6912 my $supported = grep { $_ eq $format } @$validFormats;
6913 $format = $defFormat if !$supported;
6914 return $format;
6915}
6916
ae2fcb3b
EK
6917sub resolve_first_disk {
6918 my $conf = shift;
6919 my @disks = PVE::QemuServer::valid_drive_names();
6920 my $firstdisk;
6921 foreach my $ds (reverse @disks) {
6922 next if !$conf->{$ds};
6923 my $disk = PVE::QemuServer::parse_drive($ds, $conf->{$ds});
6924 next if PVE::QemuServer::drive_is_cdrom($disk);
6925 $firstdisk = $ds;
6926 }
6927 return $firstdisk;
6928}
6929
6ee499ff 6930sub generate_uuid {
ae2fcb3b
EK
6931 my ($uuid, $uuid_str);
6932 UUID::generate($uuid);
6933 UUID::unparse($uuid, $uuid_str);
6ee499ff
DC
6934 return $uuid_str;
6935}
6936
6937sub generate_smbios1_uuid {
6938 return "uuid=".generate_uuid();
ae2fcb3b
EK
6939}
6940
9c152e87
TL
6941sub nbd_stop {
6942 my ($vmid) = @_;
6943
6944 vm_mon_cmd($vmid, 'nbd-server-stop');
6945}
6946
65e866e5
DM
6947# bash completion helper
6948
6949sub complete_backup_archives {
6950 my ($cmdname, $pname, $cvalue) = @_;
6951
6952 my $cfg = PVE::Storage::config();
6953
6954 my $storeid;
6955
6956 if ($cvalue =~ m/^([^:]+):/) {
6957 $storeid = $1;
6958 }
6959
6960 my $data = PVE::Storage::template_list($cfg, $storeid, 'backup');
6961
6962 my $res = [];
6963 foreach my $id (keys %$data) {
6964 foreach my $item (@{$data->{$id}}) {
6965 next if $item->{format} !~ m/^vma\.(gz|lzo)$/;
6966 push @$res, $item->{volid} if defined($item->{volid});
6967 }
6968 }
6969
6970 return $res;
6971}
6972
6973my $complete_vmid_full = sub {
6974 my ($running) = @_;
6975
6976 my $idlist = vmstatus();
6977
6978 my $res = [];
6979
6980 foreach my $id (keys %$idlist) {
6981 my $d = $idlist->{$id};
6982 if (defined($running)) {
6983 next if $d->{template};
6984 next if $running && $d->{status} ne 'running';
6985 next if !$running && $d->{status} eq 'running';
6986 }
6987 push @$res, $id;
6988
6989 }
6990 return $res;
6991};
6992
6993sub complete_vmid {
6994 return &$complete_vmid_full();
6995}
6996
6997sub complete_vmid_stopped {
6998 return &$complete_vmid_full(0);
6999}
7000
7001sub complete_vmid_running {
7002 return &$complete_vmid_full(1);
7003}
7004
335af808
DM
7005sub complete_storage {
7006
7007 my $cfg = PVE::Storage::config();
7008 my $ids = $cfg->{ids};
7009
7010 my $res = [];
7011 foreach my $sid (keys %$ids) {
7012 next if !PVE::Storage::storage_check_enabled($cfg, $sid, undef, 1);
c4c844ef 7013 next if !$ids->{$sid}->{content}->{images};
335af808
DM
7014 push @$res, $sid;
7015 }
7016
7017 return $res;
7018}
7019
1e3baf05 70201;