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