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